SVGの雪を降らせる

SVGの雪を降らせる

どうもGW前に風邪を何とか治して安堵しているfujiharaです。
SVGを調べていたら雪降らせたいって事で、JavaScript で降らせてみました。
(後から考えればSVGである必要はないのですが・・・)

背景

SVGについて調べていたら、丸い背景を作った段階で、季節関係なく雪を降らせたいと思いこの記事にいたりました。

HTML

まずはHTMLです。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>snow</title>

<!--load library-->
<style type="text/css">
♯wrapper,
♯wrapper svg {
  width:900px;
  height:900px;
  background-color:black;
  display:block;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="/js/snow.js"></script>
</head>

<div id="wrapper">
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
</svg>
</div>

<body>
</body>
</html>

ここでは#wrapper と SVGの側だけ用意し、表示はJavaScriptで実行します。

JavaScript

次にJavaScriptです。

$(document).ready(function() {
  /* 初期設定・表示 */
  var svgWidth = $('svg').width();                  //svg幅
  var svgHeight = $('svg').height();                //svg高さ
  var snowLength = 60;                              //雪の数
  var yStart = -30;                                 //動作開始位置(y)
  var xInterval = parseInt(svgWidth/snowLength);    //雪の間隔(x)
  var snowR = parseInt(svgWidth/(3*snowLength));    //雪の半径

  for (i=0;i<snowLength;i++) {                   //----②
    var $circle = $('<circle>', {
      'cx':xInterval + i*xInterval,                // x
      'cy':yStart,                                 // y
      'r':snowR,                                   // 半径
      'stroke':'gray',                             // 側の色
      'stroke-width':2,                            // 側の幅
      'fill':'white'                               // 内側の色
    });
    $circle.appendTo($('svg'));                    //SVGに代入
  }
  $("#wrapper").html($("#wrapper").html());       //-----③
  var $circles = $('circle');

  /* 雪を動かす */
  $circles.each(function(i) {

    var $target = $(this);
    // ランダムパラメータ
    var random = Math.ceil(i%10+i*Math.random()+Math.random()*7);
    // 下に落ちる距離
    var fallHeight = parseFloat(1.4/random);
    // Opacity減少値
    var reduceOpacity = parseFloat(0.0002/snowLength);

  // 雪ごとに1ms単位でSVGを動かす
    setInterval(function(random) {
      // 下へ移動
      $target.attr('cy',  parseFloat($target.attr('cy'))+fallHeight);
      // 徐々に透過させていく
      $target.css('opacity', parseFloat($target.css('opacity')-reduceOpacity));
      // SVGの下に30px以上言ったら、top位置に
      if (svgHeight +30 < $target.attr('cy')) {
        $target.attr('cy', yStart);
      }
      // Opacity を一定間隔でリセット
      if ($target.css('opacity') < -0.03) {
        $target.css('opacity',1);
      }
    },1);
  });
});

初期設定で雪の数や、雪の半径、スタートポジション(高さ)を設定してあげています。
そして決定した値で SVG の 円を作成し、SVGに追加していきいます。
※ここで注意ですが、③のようにDOMを更新しないとSVGが表示されませんでした。
最後に各雪ごとに落ちる動作と透過度を変更してあげます。
改善の余地が多々ある部分です。
サンプルを前回作成したHeroku環境にアップしましたので是非見てください。
デザイン的なセンスがないので、いくらでも改良が可能だと思います。

まとめ

デザインやJavaScriptコードについては改良点が多々あるとは思います。
寒い季節ではないですが今年のウィンターシーズンに使用されてみてはいかがでしょうか?

  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ