クリスマスだしcanvasで雪を降らせるJS書いてみた

こんにちは、デザイナーのスギヤマです。
今日は、クリスマスイブですね。
個人的にクリスマスは静かに雪が降っていて、綺麗と言ったイメージがあります。
なので気分だけでもそんな雰囲気を味わうべく、色々参考にしながらcanvasの勉強を兼ねて雪を振らせるJSを書いてみました。
以下で簡単説明していきます。

サンプルコード

サンプルおよび記事トップ写真 : 東京駅丸の内正面通りからの夜景

色々準備する

canvasを使うための準備をしていきます。
今回はブラウザーのウィンドウにフィットする様に表示させる方向で進めます。
canvasの表示領域は、設定しないと可変にならないようなので、
リサイズイベントを検知してcanvasのサイズを変えるよう指定します。

snow.js

/*------------------------
canvas要素の取得と設定
-------------------------*/
//canvas要素の取得
var canvas = document.getElementById('canvas');//canvasを取得
var ctx = canvas.getContext('2d');//canvasのコンテキストを取得

//canvasサイズの設定
var wd_width = window.innerWidth; //ウィンドウ幅をキャンバス幅に。
var wd_height = window.innerHeight; //ウィンドウ高をキャンバス高に。

ctx.canvas.width  = wd_width;
ctx.canvas.height = wd_height;

/*------------------------------------------------
ループ処理「requestAnimFrame」のベンダープレフィクス
-------------------------------------------------*/
var animFrame = window.requestAnimationFrame   ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            window.oRequestAnimationFrame      ||
            window.msRequestAnimationFrame     ||
            function(callback){
              window.setTimeout(callback, 1000 / 60);
            };

/*------------------------
canvasサイズを可変にする
-------------------------*/

function canvas_resize(){
  var rswd_width = window.innerWidth;
  var rswd_height = window.innerHeight;

  canvas.setAttribute('width',rswd_width);
  canvas.setAttribute('height',rswd_height);
}
//リサイズイベントを拾って実行
window.addEventListener('resize',canvas_resize,false);
canvas_resize();

雪の粒を描く

雪の粒を作成していきます。
雪の粒は、

  • 丸い
  • ふわふわしている
  • 白い

感じなので、これを表現できるようにします。
白い円が外側に向かって、グラデーションで透明になっていけば大丈夫そうです。

また、雪の粒をランダムな位置に表示したいので、乱数を使う準備が必要です。
以下の個所で諸々指定しています。

snow.js

/*------------------------
乱数
min から max までの乱整数を返す関数
Math.round() を用いると、非一様分布になります
-------------------------*/
function getRandomInt(min, max) {
  return Math.floor( Math.random() * (max - min + 1) ) + min;
}

/*------------------------
雪の設定
-------------------------*/
// 雪の粒の初期位置とサイズの設定
function snow(){
  this.position_x = getRandomInt(0, wd_width);
  this.position_y = getRandomInt(0, wd_height);
  this.snow_size = getRandomInt(1, 4);
  this.speed = getRandomInt(1, 3); //落下速度
  this.wind = getRandomInt(0, 0.5); //横風の強さ
}

// 雪の粒の描画
snow.prototype.draw = function() {
  var snow_grad  = ctx.createRadialGradient(
    this.position_x,
    this.position_y,
    this.snow_size * 0.6,
    this.position_x,
    this.position_y,
    this.snow_size
  );
  /* グラデーション終点のオフセットと色をセット */
  snow_grad.addColorStop(0,'rgba(225, 225, 225, 0.8)');
  snow_grad.addColorStop(0.5,'rgba(225, 225, 225, 0.2)');
  snow_grad.addColorStop(1,'rgba(225, 225, 225, 0.1)');
  ctx.beginPath();
  ctx.fillStyle = snow_grad; // グラデーションをfillStyleプロパティにセット
  ctx.arc( this.position_x, this.position_y, this.snow_size, 0, Math.PI * 2);
  ctx.fill();
  ctx.closePath();
}

以下を参考にしました。

これで、雪の粒が作成できました。

雪を動かす

雪の粒ができたので、今度は動かしていきます。
雪はふわふわ落ちて行くので、ただ、上から下へ移動するするのではなく、左右に揺れながら波の様な動きで落ちて欲しいです。
丁度、サイン波がそんな動きなので、使ってみます。
以下の個所で指定しています。

snow.js

snow.prototype.move = function() {
  this.position_x += this.wind + Math.sin(this.position_y/20)*0.3;
  this.position_y += this.speed;

  if (this.position_y > ctx.canvas.height) {
      this.position_y = 0;
      this.position_x = getRandomInt(0, wd_width); 
  }
}

画面内の雪の量を決める

雪の降る量を調整します。
たとえば、snow_density(80); とかで実行すると画面内に80粒の雪が降ります。
以下の個所で指定しています。

snow.js

// 雪の粒の密度(雪の量)
function snow_density(snow_count) {
  for(var num = 0; num < snow_count; num++){
    snows[num] = new snow();
  }
}

雪を降らせる

雪を降らせます。
流れとしては、

  1. 雪を初期位置に描画する
  2. 描画した雪の表示座標を更新して移動させる
  3. 1~2をくり返す

となります。
以下の個所で指定しています。

snow.js

/*------------------------
雪を降らす処理
-------------------------*/
//雪の粒を描画する
function snow_draw(){
  ctx.clearRect(0,0, wd_width, wd_height);
  for(var num = 0; num < snows.length; num++){
    snows[num].draw();
  }
}

//雪の粒の座標を更新する
function snow_move() {
  for (var num = 0; num < snows.length; num++) {
    snows[num].move();
  }
}

//ループ処理
function snowy(){
  snow_draw();
  snow_move();
  animFrame(snowy);
}

snow_density(80);
snowy();

まとめ

どうでしょう?少しはクリスマスっぽい気分になれたでしょうか?
僕は、少しはクリスマスな気持ちになりました。
まだまだ、分からないことが多いですが、canvasを使うと色々な表現ができそうで、楽しそうです。
それではみなさん、ハッピークリスマス。

参考

デザインに関するお問い合わせ

キャンペーンサイトやメディアサイト、コーポレートサイト制作など、幅広く対応致します。デザインに関するお問い合わせ、ご相談は下記ページより承っております。お気軽にお問い合わせください。

BPS x DESIGN

URL: https://design.bpsinc.jp

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

スギヤマ

2012年4月エンジニアとして入社。主業務であるバックエンド開発を担当しがてら、当時会社全体が弱かったフロントエンドも兼務。 元より「絵を描く」「デザインする」事が好きであり、プライベートな時間ではそれらをすることがもともとあり、徐々に社内のデザイナ業務も拾いながら実績と経験を積み上げる。 2017年現在、新たに2名のデザイナが入社し、ともに切磋琢磨中。

スギヤマの書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ