Last active
December 16, 2015 16:40
-
-
Save matori/5465231 to your computer and use it in GitHub Desktop.
Random Geometric Pattern Background Image with SVG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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