JavaScript:キャンバスに星型(☆)を描画する

JavaScript

よくある一筆書きで描くような星型(☆)をキャンバスに描画する方法です。

まずは基本サンプルをご覧ください。

基本のソースコード

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="main.js"></script>
    <title>星をキャンバスに描画基本</title>
    <style>
        *{ margin: 0; padding: 0; }
    </style>
</head>
<body>
    <canvas id="canvas" width="480" height="480"></canvas>
</body>
</html>

main.js

// main.js
let canvas, g;

// 星を描画する関数(中心x座標、中心y座標、半径、色)
const drawStar = function(cx, cy, r, color){
    let theta = -90;    // 角度修正(キャンバスでは3時方向が0度扱いのため12時方向を0度とする)
    let star = [];

    while(star.length < 5){   // 星の5つの頂点を求める
        const pos = {
            x: r * Math.cos(theta*Math.PI/180) + cx,
            y: r * Math.sin(theta*Math.PI/180) + cy,
        };
        star.push(pos);
        theta += 72;    // 次の点の位置:360度 ÷ 5 = 72度
    }

    // 星を描画する
    g.fillStyle = color;
    g.beginPath();  // パスの開始
    g.moveTo(star[0].x, star[0].y);
    g.lineTo(star[2].x, star[2].y);
    g.lineTo(star[4].x, star[4].y);
    g.lineTo(star[1].x, star[1].y);
    g.lineTo(star[3].x, star[3].y);
    g.closePath();  // パスを閉じる
    g.fill();
}

window.addEventListener("load", ()=>{
    // キャンバスの初期設定
    canvas = document.getElementById("canvas");
    g = canvas.getContext("2d");

    // 背景色描画
    g.fillStyle = "midnightblue";
    g.fillRect(0, 0, canvas.width, canvas.height);

    // 星を描画
    drawStar(240, 240, 80, "yellow");
});

星を描画する考え方とソースコードへの応用

まず中心(cx, cy)とした星の5つの頂点を通る円を考えます。
5等分するわけですから12時方向を最初の頂点(図の0番)とおくと72度ずつ時計回りにずらして1番から4番まで等間隔で頂点を求めることができます。(ソースコード上でもこの0~4の番号を配列starの添え字としているので分かりやすいかと思います)

72度というのは、

360度 ÷ 5等分 = 72度

だからです。

具体的には円周の0度、72度、144度、216度、288度の5つを頂点とします。

円周上のある角度(Θ)の座標(x, y)は、円の半径(r)円の中心座標(cx, cy)が分かれば次の式で求めることができます。

x = r * cos(Θ) + cx
y = r * sin(Θ) + cy

この式で求めた5つの頂点は使いやすいように配列star[0]~[4]に保存しておきます。

実際のソースコード部分

let theta = -90;
let star = [];

while(star.length < 5){   // 星の5つの頂点を求める
    const pos = {
        x: r * Math.cos(theta*Math.PI/180) + cx,
        y: r * Math.sin(theta*Math.PI/180) + cy,
    };
    star.push(pos);
    theta += 72;    // 次の点の位置:360度 ÷ 5 = 72度
}

星の頂点が求められたら、あとはキャンバスへの描画ですが、これにはmoveTo, lineToメソッドを使います。

変数theta(角度)を最初に-90としているのは、JavaScriptのキャンバスの仕様と関係があります。
キャンバスでは3時方向(右方向)の角度が0度という扱いです。12時方向を0度とするために反時計まわりに90度(-90度)にして調整しています。

最後に星の描画ですが、キャンバスのmoveToメソッドで最初の点(0番)に移動して、あとはlineToメソッドを使い

0番 → 2番 → 4番 → 1番 → 0番

と順番に一筆書きの要領で描画していきます。
最後に始点の0番に戻る部分は、closePathメソッドでOKです。

ソースコード上での描画部分

// 星を描画する
g.fillStyle = color;
g.beginPath();	// パスの開始
g.moveTo(star[0].x, star[0].y);	// ここが始点
g.lineTo(star[2].x, star[2].y);
g.lineTo(star[4].x, star[4].y);
g.lineTo(star[1].x, star[1].y);
g.lineTo(star[3].x, star[3].y);
g.closePath();	// パスを閉じる(始点に戻る)
g.fill();

星をいろいろな形で描画

今回星型(☆)を描画する部分をdrawStarという名称に関数化してあります。
せっかくなので活用してみたいと思います。

星をランダムな位置に描画

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="main.js"></script>
    <title>星をキャンバスにランダムで描画</title>
    <style>
        *{ margin: 0; padding: 0; }
    </style>
</head>
<body>
    <canvas id="canvas" width="480" height="480"></canvas>
</body>
</html>

main.js

// main.js
let canvas, g;

// 星を描画する関数(中心x座標、中心y座標、半径、色)
const drawStar = function(cx, cy, r, color){
    let theta = -90;    // 角度修正(キャンバスでは3時方向が0度扱いのため12時方向を0度とする)
    let star = [];

    while(star.length < 5){   // 星の5つの頂点を求める
        const pos = {
            x: r * Math.cos(theta*Math.PI/180) + cx,
            y: r * Math.sin(theta*Math.PI/180) + cy,
        };
        star.push(pos);
        theta += 72;    // 次の点の位置:360度 ÷ 5 = 72度
    }

    // 星を描画する
    g.fillStyle = color;
    g.beginPath();
    g.moveTo(star[0].x, star[0].y);
    g.lineTo(star[2].x, star[2].y);
    g.lineTo(star[4].x, star[4].y);
    g.lineTo(star[1].x, star[1].y);
    g.lineTo(star[3].x, star[3].y);
    g.closePath();
    g.fill();
}

window.addEventListener("load", ()=>{
    // キャンバスの初期設定
    canvas = document.getElementById("canvas");
    g = canvas.getContext("2d");

    // 背景色描画
    g.fillStyle = "midnightblue";
    g.fillRect(0, 0, canvas.width, canvas.height);

    // ランダムな位置に星を描画
    for(let i=0; i<30; i++){
        let [x, y] = [Math.random()*canvas.width, Math.random()*canvas.height];
        let r = Math.random() * 20 + 10;    // 半径 10~30の範囲
        drawStar(x, y, r, "yellow");
    }
});

星を整列して描画

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="main.js"></script>
    <title>星をキャンバスに整列して描画</title>
    <style>
        *{ margin: 0; padding: 0; }
    </style>
</head>
<body>
    <canvas id="canvas" width="480" height="480"></canvas>
</body>
</html>

main.js

// main.js
let canvas, g;

// 星を描画する関数(中心x座標、中心y座標、半径、色)
const drawStar = function(cx, cy, r, color){
    let theta = -90;    // 角度修正(キャンバスでは3時方向が0度扱いのため12時方向を0度とする)
    let star = [];

    while(star.length < 5){   // 星の5つの頂点を求める
        const pos = {
            x: r * Math.cos(theta*Math.PI/180) + cx,
            y: r * Math.sin(theta*Math.PI/180) + cy,
        };
        star.push(pos);
        theta += 72;    // 次の点の位置:360度 ÷ 5 = 72度
    }

    // 星を描画する
    g.fillStyle = color;
    g.beginPath();
    g.moveTo(star[0].x, star[0].y);
    g.lineTo(star[2].x, star[2].y);
    g.lineTo(star[4].x, star[4].y);
    g.lineTo(star[1].x, star[1].y);
    g.lineTo(star[3].x, star[3].y);
    g.closePath();
    g.fill();
}

window.addEventListener("load", ()=>{
    // キャンバスの初期設定
    canvas = document.getElementById("canvas");
    g = canvas.getContext("2d");

    // 背景色描画
    g.fillStyle = "midnightblue";
    g.fillRect(0, 0, canvas.width, canvas.height);

    // キャンバス全体に星を整列描画    
    for(let i=0; i<10; i++){
        for(let j=0; j<10; j++){
            let [x, y] = [i*48+24, j*48+24];
            drawStar(x, y, 24, "forestgreen");
        }
    }
});

星をランダムな位置にランダムカラーで描画

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="main.js"></script>
    <title>星をキャンバスにランダムで描画(色もランダム)</title>
    <style>
        *{ margin: 0; padding: 0; }
    </style>
</head>
<body>
    <canvas id="canvas" width="480" height="480"></canvas>
</body>
</html>

main.js

// main.js
let canvas, g;

// ランダムカラー文字列を生成して返す関数
function getRandomColor(){
    const get256 = ()=>{ return Math.floor(Math.random()*256); };    // 0 ~ 255を返す
    let [r, g, b] = [get256(), get256(), get256()];                 // ランダムでRGBカラーを設定
    let color = `rgb(${r}, ${g}, ${b})`;                            // 文字列生成 'rgb(XX, XXX, XXX)'
    return color;
}

// 星を描画する関数(中心x座標、中心y座標、半径、色)
const drawStar = function(cx, cy, r, color){
    let theta = -90;    // 角度修正(キャンバスでは3時方向が0度扱いのため12時方向を0度とする)
    let star = [];

    while(star.length < 5){   // 星の5つの頂点を求める
        const pos = {
            x: r * Math.cos(theta*Math.PI/180) + cx,
            y: r * Math.sin(theta*Math.PI/180) + cy,
        };
        star.push(pos);
        theta += 72;    // 次の点の位置:360度 ÷ 5 = 72度
    }

    // 星を描画する
    g.fillStyle = color;
    g.beginPath();
    g.moveTo(star[0].x, star[0].y);
    g.lineTo(star[2].x, star[2].y);
    g.lineTo(star[4].x, star[4].y);
    g.lineTo(star[1].x, star[1].y);
    g.lineTo(star[3].x, star[3].y);
    g.closePath();
    g.fill();
}

window.addEventListener("load", ()=>{
    // キャンバスの初期設定
    canvas = document.getElementById("canvas");
    g = canvas.getContext("2d");

    // 背景色描画
    g.fillStyle = "midnightblue";
    g.fillRect(0, 0, canvas.width, canvas.height);

    // ランダムな位置に星を描画
    for(let i=0; i<200; i++){
        let [x, y] = [Math.random()*canvas.width, Math.random()*canvas.height];
        let r = Math.random() * 20 + 10;    // 半径 10~30の範囲
        drawStar(x, y, r, getRandomColor() );
    }
});

1つ作ると色々と応用ができて楽しいですね!

頑張ればJavaScriptのキャンバス機能だけでガーナ共和国の国旗も描画できますよ。

参考

以上、キャンバスに星型(☆)を描画するでした。

コメント

タイトルとURLをコピーしました