HTMLのcanvas
とJavaScriptでアニメーションをやってみます。
目指すのはPSのメニュー画面の波(?)の様なアニメーションのアレ。
(背景でふわふわ揺れてる帯みたいなやつ)
完コピしようとすると3D&ライティングとかやらなきゃいけないと思うのでもう少しシンプルな物を目指す😃
(追記)最終的なコードの全文はこちら
まずはシンプルに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の幅、高さを指定する様にした。
綺麗に表示された😋
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)); },
次は波線を書いていく。
三角関数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));
表示するとこんな感じ。
美しいサイン波っすね
波線をアニメーションさせてみる。
若干カクつく瞬間があるがとりあえずOK
波の幅や高さ、位置や角度もアニメーションさせてみた。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; };
同じ要領で線をもう一本書いてcontext.closePath()
で2本の線を1つのポリゴンにし、グラデーションでフィルした。
お〜。やりたかった事がそこそこ表現できてる😇
グラデーションの色の境界の直線が強めに見えるのが不満かなー。
一旦ここまでかな〜。
最終形はポートフォリオで閲覧できます!
コードの全文はこちら
Webエンジニアをやっています
UX/UIデザインからプログラミング、DB設計、SEO、インフラ構築など幅広く対応してます
PHP/PHPUnit/Laravel/Vue/Nuxt/Docker/Terraform
ご連絡はTwitterのDMまで。