Thanks to visit codestin.com
Credit goes to github.com

Skip to content

katahiromz/5yen_hypnosis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

5yen_hypnosis

概要

JavaScriptで五円玉催眠のアニメーションを描きます。

[スクリーンショット]

コード

// 五円玉とヒモの画像
let coin_img = new Image();
coin_img.src = "coin5yen.png";

/**
 * 五円玉催眠を描画する。
 * @param {CanvasRenderingContext2D} ctx - 描画先の 2D コンテキスト
 * @param {number} x - 描画領域の左上 x 座標
 * @param {number} y - 描画領域の左上 y 座標
 * @param {number} width - 描画領域の幅
 * @param {number} height - 描画領域の高さ
 * @param {boolean} [is_blur=false] - モーションブラーをするか?
 */
const draw5YenCoinHypnosis = (ctx, x, y, width, height, is_blur = false) => {
    ctx.save(); // 現在の描画状態を保存

    // クリッピング領域を設定(指定された矩形領域外には描画しない)
    ctx.beginPath();
    ctx.rect(x, y, width, height);
    ctx.clip();

    // 描画領域の中心座標を計算
    const cx = x + width / 2, cy = y + height / 2;

    // 描画領域の寸法を分析
    const maxxy = Math.max(width, height); // 縦横の大きい方
    const minxy = Math.min(width, height); // 縦横の小さい方
    const avgxy = (maxxy + minxy) / 2;     // 平均値(未使用)

    if (false) {
        // デバッグ用:中心点に赤い十字線を描画
        ctx.beginPath();
        ctx.moveTo(cx - 10, cy); // 横線の左端
        ctx.lineTo(cx + 10, cy); // 横線の右端
        ctx.moveTo(cx, cy - 10); // 縦線の上端
        ctx.lineTo(cx, cy + 10); // 縦線の下端
        ctx.lineWidth = 1;
        ctx.strokeStyle = "red";
        ctx.stroke();
    }

    // 五円玉の画像が読み込み済みかチェック
    if (coin_img.complete) {
        // 五円玉画像の元のサイズを取得
        const c_width = coin_img.width, c_height = coin_img.height;

        // 画面サイズに合わせて画像を縮小する倍率を計算
        const s_width = minxy * 0.2; // 画面の短辺の20%のサイズに
        const s_height = s_width * c_height / c_width; // アスペクト比を維持
        const ratio = s_width / c_width; // 縮小倍率

        ctx.save(); // 座標変換前の状態を保存

        // 放射状グラデーションを作成(中心から外側に向かって色が変化)
        const rInner = 0; // 内側の半径(中心点)
        // 外側の半径は時間経過で拡大縮小(脈動効果)
        const rOuter = minxy / 2 * (1 + 0.5 * Math.sin(time / 300));
        const g = ctx.createRadialGradient(cx, cy, rInner, cx, cy, rOuter);
        g.addColorStop(0, `rgba(0, 0, 0, 100%)`);      // 中心は黒
        g.addColorStop(1, `rgba(60, 0, 91, 100%)`);    // 外側は紺色

        // 背景をグラデーションで塗りつぶす
        if (is_blur) ctx.globalAlpha = 0.2; // モーションブラーありなら、グローバルアルファを設定
        ctx.beginPath();
        ctx.rect(x, y, width, height);
        ctx.fillStyle = g;
        ctx.fill();
        if (is_blur) ctx.globalAlpha = 1.0 // 元に戻す

        // 座標変換:中心を原点に移動
        ctx.translate(cx, cy);

        // 画像を縮小
        ctx.scale(ratio, ratio);

        // 画像の中心が原点に来るように調整
        ctx.translate(-c_width/2, -c_height/2);

        // 振り子のように左右に揺れる角度を計算
        const angle = (Math.PI * 0.15) * Math.sin(time / 200); // ±27度

        // ヒモの上端のY座標(画像内での位置)
        const dy = 12;

        // 回転の支点(ヒモの上端)を原点に移動
        ctx.translate(c_width/2, dy);

        // 振り子のように回転
        ctx.rotate(angle);

        // 回転後、再び画像の描画位置に戻す
        ctx.translate(-c_width/2, -dy);

        // すべての座標変換が適用された状態で五円玉画像を描画
        ctx.drawImage(coin_img, 0, 0, c_width, c_height);

        ctx.restore(); // 座標変換を元に戻す
    }

    ctx.restore(); // 最初に保存した描画状態を復元
};

Releases

No releases published

Packages

No packages published

Languages