円や多角形をランダムに配置する背景を SVG で作る

Category : JavaScript, SVG

以前に サークルがランダムに配置される背景を SVG で作る というものを書きましたが、それを発展させて多角形も混ぜられるようにしてみました。
今回はブラーとかはありません。

多角形の座標算出は、こちらの記事を参考にしました。

対応しているのは Internet Explorer 9+, Firefox 4+, Chrome, Safari 5.1+, Opera 11.6+ です。

一応、コメントつきのも載せておきます。

(function () {

  /**
   * window がロードされたら実効
   */
  window.addEventListener('load', function () {
    geometricPatternBG({
      /**
       * 図形の頂点の数。0-2 は円、3 は三角形、4 は四角形... となる
       * 負の数は不可
       * 配列を指定すると、そこで指定された頂点数の図形をランダムに選択する
       */
      apexes: [0, 3, 4],

      /**
       * 描画する図形の数
       */
      count: 30,

      /**
       * 描画する図形の半径の最小値と最大値
       * 多角形は指定された半径の円の内側に頂点が接するサイズとなる
       */
      radius: {min: 20, max: 60},

      /**
       * RGB 値の最小値と最大値
       * 大きいほど白に近くなる
       */
      rgb: {min: 160, max: 240},

      /**
       * 図形の塗りつぶしの不透明度
       * 色は上記の RGB 値の範囲内でランダムに選択されたもの
       */
      fillOpacity: 0.3,

      /**
       * ストローク(図形の縁)の太さ
       */
      strokeWidth: 1,

      /**
       * ストロークの不透明度
       * 色は fill と同じ色
       */
      strokeOpacity: 0.5
    });
  }, false);

  /**
   * インライン SVG を作って body に追加する
   */
  function geometricPatternBG(userSettings) {

    /**
     * 初期設定
     */
    var defaultSettings = {
      apexes       : 0,
      count        : 30,
      radius       : {min: 30, max: 100},
      rgb          : {min: 150, max: 250},
      fillOpacity  : 0.2,
      strokeWidth  : 1,
      strokeOpacity: 0.3
    };

    /**
     * ユーザー設定がなければ初期設定を使用する
     */
    var options = userSettings || defaultSettings;

    /**
     * 表示領域の大きさ
     * viewBox 属性や、図形の座標指定に使う
     */
    var view = {
      width : window.innerWidth,
      height: window.innerHeight
    };

    /**
     * 関数
     */
    var fnc = {

      /**
       * SVG の要素を作る
       */
      createSVG: function (tagName) {
        return document.createElementNS('http://www.w3.org/2000/svg', tagName);
      },

      /**
       * min-max で指定された範囲内でランダムな数を返す
       * 第3引数は整数にするかどうか
       */
      getRandomNumber: function (min, max, integer) {
        var num = Math.random() * (max - min);
        if (integer) {
          num = Math.floor(num);
        }
        return num + min;
      },

      /**
       * min-max の範囲内の数値のランダムな RGB カラーコードを返す
       * rgb(255,255,255) のような文字列
       */
      getRandomRGB: function (min, max) {
        var channels = [];
        for (var i = 0; i < 3; i++) {
          channels.push(this.getRandomNumber(min, max, true));
        }
        return 'rgb(' + channels.join(',') + ')';
      },

      /**
       * 属性と値をオブジェクトでまとめて指定する
       */
      setAttributes: function (element, object) {
        for (var z in object) {
          if (object.hasOwnProperty(z)) {
            element.setAttribute(z, object[z])
          }
        }
        return element;
      },

      /**
       * スタイルをオブジェクトでまとめて指定する
       */
      setStyles: function (element, object) {
        for (var n in object) {
          if (object.hasOwnProperty(n)) {
            element.style[n] = object[n];
          }
        }
        return element;
      }
    };

    /**
     * 図形を作る
     */
    var makeFigure = {

      /**
       * 円を作る
       * 基準の座標(x, y)、 半径、色を引数で指定する
       */
      circle: function (coordinateX, coordinateY, radius, color) {

        var circle = fnc.createSVG('circle');

        circle = fnc.setAttributes(circle, {
          'cx'            : coordinateX,
          'cy'            : coordinateY,
          'r'             : radius,
          'fill'          : color,
          'stroke'        : color,
          'fill-opacity'  : options.fillOpacity,
          'stroke-width'  : options.strokeWidth,
          'stroke-opacity': options.strokeOpacity
        });

        return circle;
      },

      /**
       * 多角形を作る
       * 頂点の数、基準の座標(x, y)、 半径、色を引数で指定する
       */
      polygon: function (apexes, coordinateX, coordinateY, radius, color) {

        var polygon = fnc.createSVG('polygon');

        // 中心角 (rad)
        var centralAngleRad = (Math.PI * 2) / apexes;
        // 図形を回転させる角度
        var rotateAngleRad = fnc.getRandomNumber(0, 180, true) * Math.PI / 180;
        // 各頂点の座標を入れる配列
        var apexCoordinates = [];

        // 各頂点の座標を算出
        for (var i = 0; i < apexes; i++) {
          var x = Math.cos(centralAngleRad * i + rotateAngleRad) * radius + coordinateX;
          var y = Math.sin(centralAngleRad * i + rotateAngleRad) * radius + coordinateY;
          apexCoordinates.push(x + ',' + y);
        }

        polygon.setAttribute('points', apexCoordinates.join(' '));

        polygon = fnc.setAttributes(polygon, {
          'fill'          : color,
          'stroke'        : color,
          'fill-opacity'  : options.fillOpacity,
          'stroke-width'  : options.strokeWidth,
          'stroke-opacity': options.strokeOpacity
        });

        return polygon;
      }
    };

    /**
     * svg 要素を作成
     */
    var svg = fnc.createSVG('svg');

    /**
     * 指定された数だけ図形を作って svg 要素の子要素に
     */
    for (var i = 0, l = options.count; i < l; i++) {

      // 頂点の数
      var apx;

      /**
       * 頂点の数が配列なら、その配列からランダムに1つ選択
       * そうでなければ設定で指定された数値を使う
       */
      if (Array.isArray(options.apexes)) {
        var rand = fnc.getRandomNumber(0, options.apexes.length, true);
        apx = Math.floor(options.apexes[rand]);
      } else {
        apx = Math.floor(options.apexes);
      }

      // 図形の中心となる X 座標
      var baseX = fnc.getRandomNumber(0, view.width);
      // 図形の中心となる Y 座標
      var baseY = fnc.getRandomNumber(0, view.height);
      // 図形の半径
      var radius = fnc.getRandomNumber(options.radius.min, options.radius.max);
      // 図形の塗りつぶしの色
      var color = fnc.getRandomRGB(options.rgb.min, options.rgb.max);

      // 図形用の変数
      var figure;

      /**
       * 頂点数が 0 以上 2 以下なら円を作る
       * 3 以上ならその頂点数の多角形を作る
       */
      if (apx > -1 && apx < 3) {
        figure = makeFigure.circle(baseX, baseY, radius, color);
      } else if (apx > 2) {
        figure = makeFigure.polygon(apx, baseX, baseY, radius, color);
      }

      // svg 要素の子要素に図形を追加
      svg.appendChild(figure);
    }

    // svg 要素に viewBox 属性を指定
    svg.setAttribute('viewBox', [0, 0, view.width, view.height].join(' '));

    // svg 要素に背景として使用するためのスタイル指定をする
    svg = fnc.setStyles(svg, {
      display : 'block',
      position: 'fixed',
      zIndex  : -1,
      width   : '100%',
      height  : '100%'
    });

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

もっと改良できると思いますので、よかったら jsdo.it でフォークしてください。
それと、使うのは自由ですが何かあっても責任は負いません。

Leave a Reply