CanvasとJavaScriptでアニメーションをやってみる

HTMLcanvasJavaScriptでアニメーションをやってみます。
目指すのはPSのメニュー画面の波(?)の様なアニメーションのアレ。
(背景でふわふわ揺れてる帯みたいなやつ)
完コピしようとすると3D&ライティングとかやらなきゃいけないと思うのでもう少しシンプルな物を目指す😃

(追記)最終的なコードの全文はこちら

PS4のメニュー画面。背景のうねってる帯の様な物を真似する。

まずはシンプルにcanvasを用意して円を書く。

<canvas class="canvas" ref="canvas"></canvas>
    export default {
        mounted() {
            this.context = this.$refs.canvas.getContext('2d');
            window.requestAnimationFrame(ts => this.loop(ts));
        },
        methods   : {
            loop(timestamp) {
                const context = this.context;

                // 円を書く
                context.beginPath();
                context.fillStyle = 'rgb(0, 0, 0)';
                context.arc(10, 10, 10, 0, 2 * Math.PI);
                context.fill();

                window.requestAnimationFrame(ts => this.loop(ts));
            }
        }
    }

表示するとこんな感じ。
何故かぼやける🤔
CSSで幅と高さを指定すると駄目で、正確にはcanvasタグに幅と高さを指定しなければいけないらしい。

canvasに円を表示した状態。ぼやけている。

初期化時にcanvasの幅、高さを指定する様にした。
綺麗に表示された😋

        mounted() {
            const canvas          = this.$refs.canvas;
            const context         = this.context = canvas.getContext('2d');
            context.canvas.width  = canvas.clientWidth;
            context.canvas.height = canvas.clientHeight;
            window.requestAnimationFrame(ts => this.loop(ts));
        },
canvasに円を表示した状態。ぼやけが解消された。

次は波線を書いていく。
三角関数Math.sinなどで頑張る。

                const context = this.context;

                context.clearRect(0, 0, this.width, this.height);

                const anim = x => {
                    return Math.sin(Math.PI * x)
                };

                context.beginPath();
                context.strokeStyle = "#051560";
                context.lineWidth = 10;
                const res           = 60;
                for (var rad = 0; rad <= Math.PI; rad += Math.PI / res) {
                    const vx       = -Math.cos(rad);
                    const vy       = anim(vx);
                    const [px, py] = this.projection(vx, vy);

                    if (rad === 0) {
                        context.moveTo(px, py);
                    } else {
                        context.lineTo(px, py);
                    }
                }
                context.stroke();

                this.tick++;
                window.requestAnimationFrame(ts => this.loop(ts));

表示するとこんな感じ。
美しいサイン波っすね

canvasに波(サイン波)を表示した図

波線をアニメーションさせてみる。
若干カクつく瞬間があるがとりあえずOK

canvasのサイン波をアニメーションさせてみた図

波の幅や高さ、位置や角度もアニメーションさせてみた。
line関数で線を描画している。
animParam関数で経過フレーム数に応じてパラメータを変動させている。

                const waveHeight = 0.1 + this.animParam(0.0, 0.1, 400);
                const waveWidth  = 0.5 + this.animParam(0.1, 0.2, 800);
                const angle      = -15 + this.animParam(-15, 0, 500);
                const shiftX     = this.animParam(0.0, 1, 2000);
                const shiftY     = 0 + this.animParam(-0.1, 0.1, 300);

                const line = x => {
                    x += shiftX;
                    const y = this.angle(angle) * x + Math.sin(Math.PI * x * this.waveWidth(waveWidth)) / this.waveHeight(waveHeight)
                    return y + shiftY;
                };
canvasに表示した波を更にアニメーションさせた図

同じ要領で線をもう一本書いてcontext.closePath()で2本の線を1つのポリゴンにし、グラデーションでフィルした。
お〜。やりたかった事がそこそこ表現できてる😇
グラデーションの色の境界の直線が強めに見えるのが不満かなー。

canvasにポリゴンを表示してグラデーションした図

一旦ここまでかな〜。
最終形はポートフォリオで閲覧できます!
コードの全文はこちら

コメントする