サークルがランダムに配置される背景を SVG で作る

Category : JavaScript, SVG

SVG を使って、毎回ランダムな色・大きさ・配置でボケ(bokeh)なサークルを作ってみます。
まあやってることは前回の Kawaii Bubbles! とあんまり変わりませんけど……。
前回は li 要素を使ってやったのですが、背景として使うには適切ではないとかもなーと考えてました。で、SVG なら画像だから別にいいかと思って、今回のを作ってみました。

Random Bubbles Background with SVG スクリーンショット

Random Bubbles Background with SVG

デモファイルをダウンロード

始めは CSS Background で SVG 読み込ませようとしたり img で置こうとしたんですが、それだと SVG のスクリプトは実行されないので、HTML ファイルで読み込んでいる JavaScript で SVG 要素を作ってインライン SVG として追加することにしました。
今回の各ファイルは次のようになっています。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>タイトル</title>
<link rel="stylesheet" type="text/css" media="screen" href="style.css" />
<script type="text/javascript" src="script.js"></script>
</head>
<body>

<div class="content">
  <section>
    <h1>見出し</h1>
    <p>本文</p>
  </section>
</div>

</body>
</html>

使ったテキストは与謝野晶子の「セエヌ川」です。

html, body {
  margin : 0;
  padding: 0;
}

section {
  display: block;
}

/* for SVG */

.bg { /* 背景として使うことを考えて指定する */
  display : block;
  position: fixed;
  top     : 0;
  left    : 0;
  z-index : -1;
  width   : 100%;
  height  : 100%;
}

.blurred {
  fill-opacity: 0;   /* 塗りつぶしの不透明度 */
  stroke-width: 1.5; /* 縁の不透明度 */
}

.filled {
  fill-opacity  : 0.2; /* 塗りつぶしの不透明度 */
  stroke-width  : 1;   /* 縁の太さ */
  stroke-opacity: 0.3; /* 縁の不透明度 */
}

/* content area */

.content {
  margin     : 3em auto;
  width      : 19em;
  color      : #3a3a3a;
  font-size  : 22px;
  font-family: "Hiragino Mincho Pro W3", "MS Mincho", serif;
  text-shadow:  1px  1px 2px #fff,
                1px -1px 2px #fff,
               -1px  1px 2px #fff,
               -1px -1px 2px #fff;
}

.content h1 {
  margin     : 0;
  font-size  : 44px;
  text-indent: 1em;
  line-height: 1;
}

.content p {
  margin     : 2.5em 0;
  line-height: 1.6;
}
// この関数でインライン SVG を作って表示する
function bgSVG() {

  // 設定
  var settings = {
    count     : 30,  // 表示する泡の数
    minRadius : 20,  // 泡の半径の最小値
    maxRadius : 150, // 泡の半径の最大値
    blurRadius: 10,  // ぼかしの半径
    minRgb    : 150, // rgb 値の最小値
    maxRgb    : 255  // rgb 値の最大値
  };

  var createSvgElm = function (tagName) {
    // SVG の要素を作るための関数
    return document.createElementNS('http://www.w3.org/2000/svg', tagName);
  },
      svg = createSvgElm('svg'),             // svg 要素
      def = createSvgElm('defs'),            // defs 要素 / フィルタ用
      filter = createSvgElm('filter'),       // filter 要素
      blur = createSvgElm('feGaussianBlur'), // ブラーのための要素
      wW = window.innerWidth,
      wH = window.innerHeight,
      rand = function (min, max, integer) {
        // 範囲内でランダムな数を出す関数
        var num = Math.random() * (max - min);
        // 整数にするかどうか
        if (integer) {
          num = Math.floor(num);
        }
        return num + min;
      },
      rgb = function (min, max) {
        // 範囲内でランダムな rgb カラーコードを出す関数
        var channels = [];
        for (var i = 0; i < 3; i++) {
          channels.push(rand(min, max, true));
        }
        return 'rgb(' + channels.join(',') + ')';
      };

  // svg 要素に属性を指定
  svg.setAttribute('version', '1.1');
  svg.setAttribute('class', 'bg');

  // フィルタ用の要素と属性を作って svg 要素に追加
  filter.id = 'blur';
  blur.setAttribute('stdDeviation', settings.blurRadius);
  filter.appendChild(blur);
  def.appendChild(filter);
  svg.appendChild(def);

  // 指定した数だけバブルを作って svg 要素に追加
  for (var i = 0; i < settings.count; i++) {

    var bubble = createSvgElm('g'),       // バブル用のグループ
        blurred = createSvgElm('circle'), // 塗りつぶしなしで縁にぼかしのあるバブル
        filled = createSvgElm('circle'),  // 半透明の塗りつぶしと縁があるバブル
        posX = rand(0, wW), // X 方向の配置
        posY = rand(0, wH), // Y 方向の配置
        radius = rand(settings.minRadius, settings.maxRadius), // バブルの半径
        color = rgb(settings.minRgb, settings.maxRgb);         // バブルに使う色

    // g 要素を移動
    bubble.setAttribute('transform', 'translate(' + posX + ',' + posY + ')');

    // ぼかしバブルに各属性を指定
    blurred.setAttribute('r', radius);
    blurred.setAttribute('fill', color);
    blurred.setAttribute('stroke', color);
    blurred.setAttribute('filter', 'url(#blur)');
    blurred.setAttribute('class', 'blurred');

    // 塗りつぶしありバブルに各属性を指定
    filled.setAttribute('r', radius);
    filled.setAttribute('fill', color);
    filled.setAttribute('stroke', color);
    filled.setAttribute('class', 'filled');

    // 2つのバブルを g 要素に追加
    bubble.appendChild(blurred);
    bubble.appendChild(filled);

    // グループを svg 要素に追加
    svg.appendChild(bubble)

  }

  // HTML の body 要素に svg 要素を追加
  document.getElementsByTagName('body')[0].appendChild(svg);
}

// ウィンドウがロードされたら bgSVG を実行
window.addEventListener('load', bgSVG, false);

前回のよりは使い道あるかな……? まあ IE8 以下では何も表示されませんけど。
あと IE9, Safari 5 では SVG フィルタが使えないのでブラーはかかりません。今回のだとなんかポップな感じになってますw

まあいつも通り練習用なので使いたい人は上手いこと直しちゃってください。

Leave a Reply