Add this line into document <body>
<script type="text/javascript" src="ribbon.js"></script>
/** | |
* Ribbons Class File. | |
* Creates low-poly ribbons background effect inside a target container. | |
*/ | |
(function (name, factory) { | |
if (typeof window === "object") { | |
window[name] = factory(); | |
} | |
})("Ribbons", function () { | |
var _w = window, | |
_b = document.body, | |
_d = document.documentElement; | |
// random helper | |
var random = function () { | |
if (arguments.length === 1) // only 1 argument | |
{ | |
if (Array.isArray(arguments[0])) // extract index from array | |
{ | |
var index = Math.round(random(0, arguments[0].length - 1)); | |
return arguments[0][index]; | |
} | |
return random(0, arguments[0]); // assume numeric | |
} else if (arguments.length === 2) // two arguments range | |
{ | |
return Math.random() * (arguments[1] - arguments[0]) + arguments[0]; | |
} | |
return 0; // default | |
}; | |
// screen helper | |
var screenInfo = function (e) { | |
var width = Math.max(0, _w.innerWidth || _d.clientWidth || _b.clientWidth || 0), | |
height = Math.max(0, _w.innerHeight || _d.clientHeight || _b.clientHeight || 0), | |
scrollx = Math.max(0, _w.pageXOffset || _d.scrollLeft || _b.scrollLeft || 0) - (_d.clientLeft || 0), | |
scrolly = Math.max(0, _w.pageYOffset || _d.scrollTop || _b.scrollTop || 0) - (_d.clientTop || 0); | |
return { | |
width: width, | |
height: height, | |
ratio: width / height, | |
centerx: width / 2, | |
centery: height / 2, | |
scrollx: scrollx, | |
scrolly: scrolly | |
}; | |
}; | |
// mouse/input helper | |
var mouseInfo = function (e) { | |
var screen = screenInfo(e), | |
mousex = e ? Math.max(0, e.pageX || e.clientX || 0) : 0, | |
mousey = e ? Math.max(0, e.pageY || e.clientY || 0) : 0; | |
return { | |
mousex: mousex, | |
mousey: mousey, | |
centerx: mousex - screen.width / 2, | |
centery: mousey - screen.height / 2 | |
}; | |
}; | |
// point object | |
var Point = function (x, y) { | |
this.x = 0; | |
this.y = 0; | |
this.set(x, y); | |
}; | |
Point.prototype = { | |
constructor: Point, | |
set: function (x, y) { | |
this.x = x || 0; | |
this.y = y || 0; | |
}, | |
copy: function (point) { | |
this.x = point.x || 0; | |
this.y = point.y || 0; | |
return this; | |
}, | |
multiply: function (x, y) { | |
this.x *= x || 1; | |
this.y *= y || 1; | |
return this; | |
}, | |
divide: function (x, y) { | |
this.x /= x || 1; | |
this.y /= y || 1; | |
return this; | |
}, | |
add: function (x, y) { | |
this.x += x || 0; | |
this.y += y || 0; | |
return this; | |
}, | |
subtract: function (x, y) { | |
this.x -= x || 0; | |
this.y -= y || 0; | |
return this; | |
}, | |
clampX: function (min, max) { | |
this.x = Math.max(min, Math.min(this.x, max)); | |
return this; | |
}, | |
clampY: function (min, max) { | |
this.y = Math.max(min, Math.min(this.y, max)); | |
return this; | |
}, | |
flipX: function () { | |
this.x *= -1; | |
return this; | |
}, | |
flipY: function () { | |
this.y *= -1; | |
return this; | |
} | |
}; | |
// class constructor | |
var Factory = function (options) { | |
this._canvas = null; | |
this._context = null; | |
this._sto = null; | |
this._width = 0; | |
this._height = 0; | |
this._scroll = 0; | |
this._ribbons = []; | |
this._options = { | |
// ribbon color HSL saturation amount | |
colorSaturation: "80%", | |
// ribbon color HSL brightness amount | |
colorBrightness: "60%", | |
// ribbon color opacity amount | |
colorAlpha: 0.65, | |
// how fast to cycle through colors in the HSL color space | |
colorCycleSpeed: 6, | |
// where to start from on the Y axis on each side (top|min, middle|center, bottom|max, random) | |
verticalPosition: "center", | |
// how fast to get to the other side of the screen | |
horizontalSpeed: 200, | |
// how many ribbons to keep on screen at any given time | |
ribbonCount: 3, | |
// add stroke along with ribbon fill colors | |
strokeSize: 0, | |
// move ribbons vertically by a factor on page scroll | |
parallaxAmount: -0.5, | |
// add animation effect to each ribbon section over time | |
animateSections: true | |
}; | |
this._onDraw = this._onDraw.bind(this); | |
this._onResize = this._onResize.bind(this); | |
this._onScroll = this._onScroll.bind(this); | |
this.setOptions(options); | |
this.init(); | |
}; | |
// class prototype | |
Factory.prototype = { | |
constructor: Factory, | |
// Set and merge local options | |
setOptions: function (options) { | |
if (typeof options === "object") { | |
for (var key in options) { | |
if (options.hasOwnProperty(key)) { | |
this._options[key] = options[key]; | |
} | |
} | |
} | |
}, | |
// Initialize the ribbons effect | |
init: function () { | |
try { | |
this._canvas = document.createElement("canvas"); | |
this._canvas.style["display"] = "block"; | |
this._canvas.style["position"] = "fixed"; | |
this._canvas.style["margin"] = "0"; | |
this._canvas.style["padding"] = "0"; | |
this._canvas.style["border"] = "0"; | |
this._canvas.style["outline"] = "0"; | |
this._canvas.style["left"] = "0"; | |
this._canvas.style["top"] = "0"; | |
this._canvas.style["width"] = "100%"; | |
this._canvas.style["height"] = "100%"; | |
this._canvas.id = "bgCanvas"; | |
this._onResize(); | |
this._context = this._canvas.getContext("2d"); | |
this._context.clearRect(0, 0, this._width, this._height); | |
this._context.globalAlpha = this._options.colorAlpha; | |
window.addEventListener("resize", this._onResize); | |
window.addEventListener("scroll", this._onScroll); | |
document.body.appendChild(this._canvas); | |
} catch (e) { | |
console.warn("Canvas Context Error: " + e.toString()); | |
return; | |
} | |
this._onDraw(); | |
}, | |
// Create a new random ribbon and to the list | |
addRibbon: function () { | |
// movement data | |
var dir = Math.round(random(1, 9)) > 5 ? "right" : "left", | |
stop = 1000, | |
hide = 200, | |
min = 0 - hide, | |
max = this._width + hide, | |
movex = 0, | |
movey = 0, | |
startx = dir === "right" ? min : max, | |
starty = Math.round(random(0, this._height)); | |
// asjust starty based on options | |
if (/^(top|min)$/i.test(this._options.verticalPosition)) { | |
starty = hide; | |
} else if (/^(middle|center)$/i.test(this._options.verticalPosition)) { | |
starty = this._height / 2; | |
} else if (/^(bottom|max)$/i.test(this._options.verticalPosition)) { | |
starty = this._height - hide; | |
} | |
// ribbon sections data | |
var ribbon = [], | |
point1 = new Point(startx, starty), | |
point2 = new Point(startx, starty), | |
point3 = null, | |
color = Math.round(random(0, 360)), | |
delay = 0; | |
// buils ribbon sections | |
while (true) { | |
if (stop <= 0) break; | |
stop--; | |
movex = Math.round((Math.random() - 0.2) * this._options.horizontalSpeed); | |
movey = Math.round((Math.random() - 0.5) * (this._height * 0.25)); | |
point3 = new Point(); | |
point3.copy(point2); | |
if (dir === "right") { | |
point3.add(movex, movey); | |
if (point2.x >= max) break; | |
} else if (dir === "left") { | |
point3.subtract(movex, movey); | |
if (point2.x <= min) break; | |
} | |
// point3.clampY( 0, this._height ); | |
ribbon.push({ // single ribbon section | |
point1: new Point(point1.x, point1.y), | |
point2: new Point(point2.x, point2.y), | |
point3: point3, | |
color: color, | |
delay: delay, | |
dir: dir, | |
alpha: 0, | |
phase: 0 | |
}); | |
point1.copy(point2); | |
point2.copy(point3); | |
delay += 4; | |
color += this._options.colorCycleSpeed; | |
} | |
this._ribbons.push(ribbon); | |
}, | |
// Draw single section | |
_drawRibbonSection: function (section) { | |
if (section) { | |
if (section.phase >= 1 && section.alpha <= 0) { | |
return true; // done | |
} | |
if (section.delay <= 0) { | |
section.phase += 0.02; | |
section.alpha = Math.sin(section.phase); | |
section.alpha = section.alpha <= 0 ? 0 : section.alpha; | |
section.alpha = section.alpha >= 1 ? 1 : section.alpha; | |
if (this._options.animateSections) { | |
var mod = Math.sin(1 + section.phase * Math.PI / 2) * 0.1; | |
if (section.dir === "right") { | |
section.point1.add(mod, 0); | |
section.point2.add(mod, 0); | |
section.point3.add(mod, 0); | |
} else { | |
section.point1.subtract(mod, 0); | |
section.point2.subtract(mod, 0); | |
section.point3.subtract(mod, 0); | |
} | |
section.point1.add(0, mod); | |
section.point2.add(0, mod); | |
section.point3.add(0, mod); | |
} | |
} else { | |
section.delay -= 0.5; | |
} | |
var s = this._options.colorSaturation, | |
l = this._options.colorBrightness, | |
c = "hsla(" + section.color + ", " + s + ", " + l + ", " + section.alpha + " )"; | |
this._context.save(); | |
if (this._options.parallaxAmount !== 0) { | |
this._context.translate(0, this._scroll * this._options.parallaxAmount); | |
} | |
this._context.beginPath(); | |
this._context.moveTo(section.point1.x, section.point1.y); | |
this._context.lineTo(section.point2.x, section.point2.y); | |
this._context.lineTo(section.point3.x, section.point3.y); | |
this._context.fillStyle = c; | |
this._context.fill(); | |
if (this._options.strokeSize > 0) { | |
this._context.lineWidth = this._options.strokeSize; | |
this._context.strokeStyle = c; | |
this._context.lineCap = "round"; | |
this._context.stroke(); | |
} | |
this._context.restore(); | |
} | |
return false; // not done yet | |
}, | |
// Draw ribbons | |
_onDraw: function () { | |
// cleanup on ribbons list to rtemoved finished ribbons | |
for (var i = 0, t = this._ribbons.length; i < t; ++i) { | |
if (!this._ribbons[i]) { | |
this._ribbons.splice(i, 1); | |
} | |
} | |
// draw new ribbons | |
this._context.clearRect(0, 0, this._width, this._height); | |
for (var a = 0; a < this._ribbons.length; ++a) // single ribbon | |
{ | |
var ribbon = this._ribbons[a], | |
numSections = ribbon.length, | |
numDone = 0; | |
for (var b = 0; b < numSections; ++b) // ribbon section | |
{ | |
if (this._drawRibbonSection(ribbon[b])) { | |
numDone++; // section done | |
} | |
} | |
if (numDone >= numSections) // ribbon done | |
{ | |
this._ribbons[a] = null; | |
} | |
} | |
// maintain optional number of ribbons on canvas | |
if (this._ribbons.length < this._options.ribbonCount) { | |
this.addRibbon(); | |
} | |
requestAnimationFrame(this._onDraw); | |
}, | |
// Update container size info | |
_onResize: function (e) { | |
var screen = screenInfo(e); | |
this._width = screen.width; | |
this._height = screen.height; | |
if (this._canvas) { | |
this._canvas.width = this._width; | |
this._canvas.height = this._height; | |
if (this._context) { | |
this._context.globalAlpha = this._options.colorAlpha; | |
} | |
} | |
}, | |
// Update container size info | |
_onScroll: function (e) { | |
var screen = screenInfo(e); | |
this._scroll = screen.scrolly; | |
} | |
}; | |
// export | |
return Factory; | |
}); | |
new Ribbons(); |