Skip to content

Instantly share code, notes, and snippets.

@matori
Last active December 16, 2015 16:40
Show Gist options
  • Save matori/5465231 to your computer and use it in GitHub Desktop.
Save matori/5465231 to your computer and use it in GitHub Desktop.
Random Geometric Pattern Background Image with SVG
(function (w) {
if (w.GPBG) {
var gpbg = new GPBG();
if (w.addEventListener) {
var draw = function () {
gpbg.draw('body', {
apexes : [0, 3, 4, 5],
count : 25,
maxRadius : 80,
fillOpacity : 0.4,
strokeWidth : 5,
strokeOpacity: 1
});
gpbg.draw('div:first-child', {
count : 20,
minRadius : 10,
maxRadius : 40,
fillOpacity : 0.1,
strokeOpacity: 0.1
});
gpbg.draw('div:nth-child(2)', {
apexes : [3],
count : 50,
minRadius : 20,
maxRadius : 20,
fillOpacity : 0,
strokeWidth : 3,
strokeOpacity: 0.2
})
};
w.addEventListener('DOMContentLoaded', draw, false);
}
gpbg.die();
}
})(window);
jQuery(function ($) {
var gpbg = new GPBG();
var svg = gpbg.getImage(500, 500, {
apexes : [3, 4, 5],
count : 20,
minRadius : 10,
maxRadius : 80,
fillOpacity : 0.4,
strokeWidth : 5,
strokeOpacity: 1
});
svg = gpbg.svgToDataUrl(svg);
var img = $('<img/>').attr('src', svg);
$('body').append(img);
gpbg.die();
});
/**
* @fileOverview
* @name GPBG.js
* @author Matori
* @license MIT License
*/
(function (w, d) {
'use strict';
var namespace = 'GPBG';
var GeometricPatternBG = function () {
// SVG の名前空間
this._svgns = 'http://www.w3.org/2000/svg';
// 実行可能かどうか
this._activate = false;
// 初期化
this._init();
};
GeometricPatternBG.prototype = {
/**
* 初期設定
*/
_getDefault: function () {
return {
/**
* 描画する図形の頂点数 (0-2: circle, 3: triangle, 4: square...)
* @type {Array}
*/
apexes : [0],
/**
* 図形をいくつ描画するか
* @type {Number}
*/
count : 30,
/**
* 図形の最小半径
* @type {Number}
*/
minRadius : 20,
/**
* 図形の最大半径
* @type {Number}
*/
maxRadius : 60,
/**
* 図形に使う色の最小 RGB 値 (0-255)
* @type {Number}
*/
minRgbRange : 160,
/**
* 図形に使う色の最大 RGB 値 (0-255)
* @type {Number}
*/
maxRgbRange : 240,
/**
* 図形の塗りつぶし色の不透明度 (0-1)
* @type {Number}
*/
fillOpacity : 0.3,
/**
* 図形の縁取りの太さ
* @type {Number}
*/
strokeWidth : 1,
/**
* 図形の縁取り色の不透明度 (0-1)
* @type {Number}
*/
strokeOpacity: 0.5,
/**
* グレースケールにするかどうか
* @type {Boolean}
*/
grayscale : false
};
},
/**
* 初期化
*/
_init: function () {
var that = this;
// 実行可能かどうか確認
if (!!d.createElementNS && !!d.createElementNS(that._svgns, 'svg').createSVGRect && !!Object.keys && !!w.XMLSerializer) {
that._activate = true;
}
// 実行可能なら……
if (that._activate === true) {
// スタイルシートを新たに作り、<head> に追加
d.getElementsByTagName('head')[0].appendChild(d.createElement('style'));
this._css = d.styleSheets[d.styleSheets.length - 1];
// SVG を文字列にするときに使う
that._xmlSerializer = new XMLSerializer();
// SVG を文字列にしたたときに、xmlns="" があるかどうか確認 (Chrome 対策)
that._xmlnsString = checkXmlnsString();
}
/**
* SVG を文字列にしたたときに、xmlns="" があるかどうか
* IE, Firefox, Opera (Presto) にはあるが Chrome にはない
*/
function checkXmlnsString() {
// svg 要素を作成
var svg = that._createElementSVG('svg');
// 作った SVG を文字列に
var svgString = that._xmlSerializer.serializeToString(svg);
// 文字列内に xmlns があるかどうかを返す
return (svgString.indexOf('xmlns') > 0);
}
},
/**
* グローバルオブジェクトから名前空間を削除する
*/
die: function () {
try {
delete w[namespace];
} catch (e) {
// delete できなかったら void 0 を代入する
w[namespace] = void 0;
}
},
/**
* 指定されたセレクタの背景画像に SVG 画像を Data URL で指定する
* スタイルは新たに作ったスタイルシートで指定する
*/
draw: function (selector, userSettings) {
var that = this;
var targetElements;
var targetHeight;
var targetWidth;
var bgImg;
// 実行可能でなければ何もせずに終了
if (that._activate === false) {
return;
}
// 指定されたセレクタに一致する要素セットを取得
targetElements = d.querySelectorAll(selector);
// 一致するものがなかったら終了
if (targetElements.length === 0) {
return;
}
// 一致するものが複数ある場合
if (targetElements.length > 1) {
// それらの中から最大の高さと幅を取得
getMaxSize(targetElements);
} else {
// 一つだったら、その要素の高さと幅を取得
targetHeight = targetElements[0].clientHeight;
targetWidth = targetElements[0].clientWidth;
// 一つで、その要素が body であった場合
if (targetElements[0].tagName.toLowerCase() === 'body') {
// ウィンドウサイズと比較して大きいほうを採用
targetHeight = targetHeight < w.innerHeight ? w.innerHeight : targetHeight;
targetWidth = targetWidth < w.innerWidth ? w.innerWidth : targetWidth;
}
}
// SVG を作る
bgImg = that.getImage(targetWidth, targetHeight, userSettings);
// 作った SVG を Data URL にして CSS 用の文字列に
bgImg = 'url("' + that.svgToDataUrl(bgImg) + '")';
// スタイルシートに該当セレクタの背景画像に Data URL にした SVG を指定したものを追加
that._css.insertRule(selector + '{background-image:' + bgImg + '}', that._css.cssRules.length);
/**
* 要素セットの中から最大の高さと幅を取得して変数に入れる
*/
function getMaxSize(elements) {
var heightArray = [];
var widthArray = [];
for (var i = 0, iz = elements.length; i < iz; ++i) {
heightArray.push(elements[i].clientHeight);
widthArray.push(elements[i].clientWidth);
}
targetHeight = Math.max.apply(null, heightArray);
targetWidth = Math.max.apply(null, widthArray);
}
},
/**
* SVG 画像を作成する
*/
getImage: function (width, height, settings) {
var that = this;
var options;
// 実行可能でなければ終了
if (that._activate === false) {
return false;
}
// 設定指定がなければ代わりに空のオブジェクトに
settings = settings || {};
// 指定された設定で初期設定を上書き
options = that._extend(this._getDefault(), settings);
// SVG 画像を作成
return that._createImage(width, height, options);
},
/**
* SVG を Data URL に変換する関数
*/
svgToDataUrl: function (svg) {
var svgString;
// 実行可能でなければ終了
if (this._activate === false) {
return false;
}
// SVG を文字列に変換
svgString = this._xmlSerializer.serializeToString(svg);
// データ形式を先頭に追加
svgString = 'data:image/svg+xml,' + encodeURIComponent(svgString);
return svgString;
},
/**
* オブジェクトを上書きする
*/
_extend: function (baseObject, newObject) {
// オブジェクトキーを配列に
var keys = Object.keys(newObject);
// 同じキーを上書き
for (var i = 0, iz = keys.length; i < iz; ++i) {
baseObject[keys[i]] = newObject[keys[i]];
}
return baseObject;
},
/**
* SVG の要素を作る
*/
_createElementSVG: function (name, attributes) {
var svgElement = d.createElementNS(this._svgns, name);
if (attributes && Object.keys(attributes).length > 0) {
svgElement = this._setAttributes(svgElement, attributes);
}
return svgElement;
},
/**
* 属性と値をまとめて指定する
*/
_setAttributes: function (element, attributes) {
var keys = Object.keys(attributes);
for (var i = 0, iz = keys.length; i < iz; ++i) {
element.setAttribute(keys[i], attributes[keys[i]]);
}
return element;
},
/**
* 指定範囲内でランダムな数値を得る
*/
_getRandomNumber: function (min, max, integer) {
integer = integer || true;
var num = Math.random() * (max - min);
if (integer === true) {
num = Math.floor(num);
}
return num + min;
},
/**
* 図形を作る
* circle 要素、または polygon 要素
*/
_createFigure: function (apexes, obj) {
var that = this;
var figure;
if (apexes === 0) {
// 頂点数が 0 なら円を作る
figure = that._createElementSVG('circle', {
'cx': obj.coordinateX,
'cy': obj.coordinateY,
'r' : obj.radius
});
} else {
// そうでなければ多角形を作る
figure = that._createElementSVG('polygon', {
'points': getApexCoordinates()
});
}
// 円でも多角形でも共通の属性をまとめて指定する
figure = that._setAttributes(figure, {
'fill' : obj.color,
'stroke' : obj.color,
'fill-opacity' : obj.fillOpacity,
'stroke-width' : obj.strokeWidth,
'stroke-opacity': obj.strokeOpacity
});
return figure;
/**
* 多角形の points 属性値を作成
*/
function getApexCoordinates() {
var centralAngleRad = (Math.PI * 2) / apexes;
var rotateAngleRad = that._getRandomNumber(0, 180) * Math.PI / 180;
var apexCoordinates = [];
for (var i = 0; i < apexes; ++i) {
var x = Math.cos(centralAngleRad * i + rotateAngleRad) * obj.radius + obj.coordinateX;
var y = Math.sin(centralAngleRad * i + rotateAngleRad) * obj.radius + obj.coordinateY;
apexCoordinates.push(x + ',' + y);
}
return apexCoordinates.join(' ');
}
},
/**
* SVG 画像を作成
* getImage() から使われる
*/
_createImage: function (targetWidth, targetHeight, options) {
var that = this;
// svg 要素を作成
var svg = that._createElementSVG('svg', {
'version': '1.1',
'width' : targetWidth,
'height' : targetHeight,
'viewBox': [0, 0, targetWidth, targetHeight].join(' ')
});
var figure;
var apexes;
var apexesLength = options.apexes.length;
// 文字列にしたときに xmlns がないブラウザだけ xmlns 属性を追加
if (!that._xmlnsString) {
that._setAttributes(svg, {
'xmlns': that._svgns
});
}
// 図形を作って svg 要素に追加
for (var i = 0, iz = options.count; i < iz; ++i) {
if (apexesLength > 1) {
apexes = options.apexes[that._getRandomNumber(0, apexesLength)];
} else {
apexes = options.apexes[0];
}
if (apexes < 3) {
apexes = 0;
}
figure = that._createFigure(apexes, {
coordinateX : that._getRandomNumber(0, targetWidth, false),
coordinateY : that._getRandomNumber(0, targetHeight, false),
radius : (options.minRadius === options.maxRadius) ?
options.minRadius :
that._getRandomNumber(options.minRadius, options.maxRadius, false),
color : randomRGB(),
fillOpacity : options.fillOpacity,
strokeWidth : options.strokeWidth,
strokeOpacity: options.strokeOpacity
});
svg.appendChild(figure);
}
return svg;
// 指定範囲内でランダムな RGB カラーコードを作成
function randomRGB() {
var channels = [];
if (options.grayscale === false) {
for (var i = 0; i < 3; ++i) {
channels.push(that._getRandomNumber(options.minRgbRange, options.maxRgbRange));
}
} else {
// グレースケール指定なら全て同じ値に
channels[0] = channels[1] = channels[2] = that._getRandomNumber(options.minRgbRange, options.maxRgbRange);
}
return 'rgb(' + channels.join(',') + ')';
}
}
};
// グローバルオブジェクトを作成
w[namespace] = GeometricPatternBG;
})(window, document);
/**
* @fileOverview
* @name GPBG.js
* @author Matori
* @license MIT License
*/
(function(f,g){var h=function(){this._svgns="http://www.w3.org/2000/svg";this._activate=!1;this._init()};h.prototype={_getDefault:function(){return{apexes:[0],count:30,minRadius:20,maxRadius:60,minRgbRange:160,maxRgbRange:240,fillOpacity:0.3,strokeWidth:1,strokeOpacity:0.5,grayscale:!1}},_init:function(){g.createElementNS&&(g.createElementNS(this._svgns,"svg").createSVGRect&&Object.keys&&f.XMLSerializer)&&(this._activate=!0);if(!0===this._activate){g.getElementsByTagName("head")[0].appendChild(g.createElement("style"));
this._css=g.styleSheets[g.styleSheets.length-1];this._xmlSerializer=new XMLSerializer;var c=this._createElementSVG("svg");this._xmlnsString=0<this._xmlSerializer.serializeToString(c).indexOf("xmlns")}},die:function(){try{delete f.GPBG}catch(c){f.GPBG=void 0}},draw:function(c,b){var a,e,d;if(!1!==this._activate&&(a=g.querySelectorAll(c),0!==a.length)){if(1<a.length){e=[];d=[];for(var j=0,m=a.length;j<m;++j)e.push(a[j].clientHeight),d.push(a[j].clientWidth);e=Math.max.apply(null,e);d=Math.max.apply(null,
d)}else e=a[0].clientHeight,d=a[0].clientWidth,"body"===a[0].tagName.toLowerCase()&&(e=e<f.innerHeight?f.innerHeight:e,d=d<f.innerWidth?f.innerWidth:d);a=this.getImage(d,e,b);a='url("'+this.svgToDataUrl(a)+'")';this._css.insertRule(c+"{background-image:"+a+"}",this._css.cssRules.length)}},getImage:function(c,b,a){if(!1===this._activate)return!1;a=a||{};a=this._extend(this._getDefault(),a);return this._createImage(c,b,a)},svgToDataUrl:function(c){if(!1===this._activate)return!1;c=this._xmlSerializer.serializeToString(c);
return c="data:image/svg+xml,"+encodeURIComponent(c)},_extend:function(c,b){for(var a=Object.keys(b),e=0,d=a.length;e<d;++e)c[a[e]]=b[a[e]];return c},_createElementSVG:function(c,b){var a=g.createElementNS(this._svgns,c);b&&0<Object.keys(b).length&&(a=this._setAttributes(a,b));return a},_setAttributes:function(c,b){for(var a=Object.keys(b),e=0,d=a.length;e<d;++e)c.setAttribute(a[e],b[a[e]]);return c},_getRandomNumber:function(c,b,a){a=a||!0;b=Math.random()*(b-c);!0===a&&(b=Math.floor(b));return b+
c},_createFigure:function(c,b){function a(){for(var a=2*Math.PI/c,d=e._getRandomNumber(0,180)*Math.PI/180,f=[],g=0;g<c;++g){var k=Math.cos(a*g+d)*b.radius+b.coordinateX,n=Math.sin(a*g+d)*b.radius+b.coordinateY;f.push(k+","+n)}return f.join(" ")}var e=this,d;d=0===c?e._createElementSVG("circle",{cx:b.coordinateX,cy:b.coordinateY,r:b.radius}):e._createElementSVG("polygon",{points:a()});return d=e._setAttributes(d,{fill:b.color,stroke:b.color,"fill-opacity":b.fillOpacity,"stroke-width":b.strokeWidth,
"stroke-opacity":b.strokeOpacity})},_createImage:function(c,b,a){function e(){var b=[];if(!1===a.grayscale)for(var c=0;3>c;++c)b.push(d._getRandomNumber(a.minRgbRange,a.maxRgbRange));else b[0]=b[1]=b[2]=d._getRandomNumber(a.minRgbRange,a.maxRgbRange);return"rgb("+b.join(",")+")"}var d=this,g=d._createElementSVG("svg",{version:"1.1",width:c,height:b,viewBox:[0,0,c,b].join(" ")}),f,h=a.apexes.length;d._xmlnsString||d._setAttributes(g,{xmlns:d._svgns});for(var l=0,k=a.count;l<k;++l)f=1<h?a.apexes[d._getRandomNumber(0,
h)]:a.apexes[0],3>f&&(f=0),f=d._createFigure(f,{coordinateX:d._getRandomNumber(0,c,!1),coordinateY:d._getRandomNumber(0,b,!1),radius:a.minRadius===a.maxRadius?a.minRadius:d._getRandomNumber(a.minRadius,a.maxRadius,!1),color:e(),fillOpacity:a.fillOpacity,strokeWidth:a.strokeWidth,strokeOpacity:a.strokeOpacity}),g.appendChild(f);return g}};f.GPBG=h})(window,document);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment