var settings = {
timeRandom: 1000, // max time in ms between random Fireworks
particlesBase: 80, // min number of particles per Firework
particlesRandom: 20, // max number of additional random particles per firework
sizeBase: 8, // min size of particles
sizeRandom: 10, // max additional random size
velocityBase: 4, // min velocity of particles
velocityRandom: 4, // max additional random velocity
lifetimeBase: 800, // min lifetime of particle
lifetimeRandom: 400, // max additional random lifetime
gravity: 0.06 // gravity of particles
}
;(function(require, window, document, undefined) {
require.config({
baseUrl: 'http://cdn.qoopido.com/portfolio/assets/vendor/qoopido.js/dist/3.5.0/min'
});
var MATH_PI_TIMES_TWO = 2 * Math.PI,
MATH_PI_DIV_TWO = Math.PI / 2,
COLORS = [ '33,141,166', '149,186,0', '255,180,0', '166,60,148', '255,255,51', '255,0,102', '255,140,0' ],
EASINGS = [ easeInSine, easeInQuad, easeInCubic ];
function easeInSine(t, d) {
return 1 * Math.cos(t / d * MATH_PI_DIV_TWO) -1 + 1;
}
function easeInQuad(t, d) {
return -1 * (t /= d) * t + 1;
}
function easeInCubic(t, d) {
return -1 * (t /= d) * t * t + 1;
}
require([ 'base' ], function() {
require([ 'pool/module', 'pool/dom', 'pool/array', 'pool/object' ], function(mPoolModule, mPoolDom) {
require([ 'support', 'renderer', 'particle', 'dom/element', 'dom/collection', 'vector/2d' ], function(mSupport, mRenderer, mParticle, mDomElement, mDomCollection, mVector) {
var qWindow = mDomElement.create(window),
qCanvas = mDomElement.create('').insertBefore('#console'),
qCanvasElement = qCanvas.element,
qCanvasContext = qCanvasElement.getContext('2d'),
renderer = mRenderer,
poolModule = mPoolModule.create(mParticle),
poolDom = mPoolDom.create(),
poolVector = mPoolModule.create(mVector),
poolMetrics = poolModule.metrics,
consoleFps = mDomElement.create('#fps'),
consoleTotal = mDomElement.create('#total'),
consoleRecycled = mDomElement.create('#recycled'),
consoleDestroyed = mDomElement.create('#destroyed'),
consoleInPool = mDomElement.create('#inpool'),
consoleInUse = mDomElement.create('#inuse'),
consoleInQueue = mDomElement.create('#inqueue'),
width = 0, height = 0, now = new Date().getTime(), last = now, delta = 0, fps = 60, ratio = 1, particles = [], paused = false;
function generateRandomFirework() {
if(paused === false) {
addFirework();
}
setTimeout(generateRandomFirework, Math.random() * settings.timeRandom);
}
function addFirework(event) {
var count = ((Math.random() * settings.particlesRandom + settings.particlesBase) / ratio) >> 0,
x = event ? parseInt(event.clientX || event.pageX, 10) : (Math.random() * width) >> 0,
y = event ? parseInt(event.clientY || event.pageY, 10) : (Math.random() * height) >> 0,
angle = MATH_PI_TIMES_TWO / count,
color = ''.concat('rgba(', COLORS[((Math.random() * (COLORS.length - 1)) + 0.5) >> 0], ','),
size = (size = ((Math.random() * settings.sizeRandom) >> 0) + settings.sizeBase) + (size % 2),
canvas = poolDom.obtain('canvas'),
acceleration = poolVector.obtain(0, settings.gravity),
hSize, context, fill;
canvas.width = canvas.height = size;
canvas.usage = count;
acceleration.usage = count;
hSize = size / 2;
context = canvas.getContext('2d');
fill = context.createRadialGradient(hSize, hSize, 0, hSize, hSize, hSize);
fill.addColorStop(0, ''.concat(color, '1)'));
fill.addColorStop(1, ''.concat(color, '0)'));
context.arc(hSize, hSize, hSize, 0, MATH_PI_TIMES_TWO, false);
context.fillStyle = fill;
context.fill();
while(count--) {
var randomVelocity = settings.velocityBase + Math.random() * settings.velocityRandom,
particleAngle = count * angle,
particle = poolModule.obtain(x, y);
particle.velocity.x = Math.cos(particleAngle) * randomVelocity;
particle.velocity.y = Math.sin(particleAngle) * randomVelocity;
particle.acceleration.push(acceleration);
particle.canvas = canvas;
particle.size = size;
particle.easing = particle.easing ? particle.easing : EASINGS[(Math.random() * (EASINGS.length - 1) + 0.5) >> 0];
particle.birthtime = now;
particle.lifetime = particle.lifetime? particle.lifetime : (settings.lifetimeBase + Math.random() * settings.lifetimeRandom) >> 0;
particle.deathtime = now + particle.lifetime;
particles.push(particle);
}
if(event) {
event.preventDefault();
event.stopPropagation();
return false;
}
}
function renderParticle(particle) {
qCanvasContext.save();
qCanvasContext.globalCompositeOperation = 'lighter';
qCanvasContext.globalAlpha = Math.random() * particle.easing(now - particle.birthtime, particle.lifetime);
qCanvasContext.drawImage(particle.canvas, particle.position.x >> 0, particle.position.y >> 0);
qCanvasContext.restore();
}
function initializeSettings() {
var definitions = {};
mDomCollection
.create('#console [data-setting]')
.each(function() {
var self = this,
parameter = self.getAttribute('data-setting').split(':'),
setting = parameter[0],
range = parameter[1].split(','),
stepping = parseFloat(range.pop()),
previous = mDomElement.create('', { 'data-control': setting }).addClass('previous').setContent('-').appendTo(self),
value = mDomElement.create('').addClass('value').setContent(settings[setting]).appendTo(self),
next = mDomElement.create('', { 'data-control': setting }).addClass('next').setContent('+').appendTo(self);
definitions[setting] = {
value: value,
range: range,
stepping: stepping
}
});
mDomElement
.create('#console')
.on('click', '[data-control]', function(event) {
var self = mDomElement.create(this),
setting = self.getAttribute('data-control'),
definition = definitions[setting];
event.preventDefault();
event.stopPropagation();
if(self.hasClass('previous')) {
definition.value.setContent(settings[setting] = Math.max(definition.range[0], Math.min(definition.range[1], settings[setting] - definition.stepping)));
} else if(self.hasClass('next')) {
definition.value.setContent(settings[setting] = Math.max(definition.range[0], Math.min(definition.range[1], settings[setting] + definition.stepping)));
}
return false;
});
}
function onResize() {
width = qCanvasElement.width = window.innerWidth;
height = qCanvasElement.height = window.innerHeight;
}
function onTick(type, lFps, lRatio) {
var i = 0, particle, position, size, canvas, acceleration;
now = new Date().getTime();
fps = (fps + lFps) / 2;
ratio = lRatio;
delta = now - last;
qCanvasContext.fillStyle = 'rgba(0,0,0,0.15)';
qCanvasContext.fillRect(0, 0, width, height);
for(; (particle = particles[i]) !== undefined; i++) {
particle.update();
position = particle.position;
size = particle.size;
if(now > particle.deathtime || position.x < -size || position.y < -size || position.x > width + size || position.y > height + size) {
particles.splice(i, 1);
canvas = particle.canvas,
acceleration = particle.acceleration[0];
particle.dispose();
canvas.usage -= 1;
acceleration.usage -= 1;
if(canvas.usage <= 0) {
canvas = particle.canvas = canvas.dispose();
}
if(acceleration.usage <= 0) {
acceleration = acceleration.dispose();
}
i -= 1;
} else {
renderParticle(particle);
}
}
if(delta > 1000) {
consoleFps.setContent(fps >> 0);
last = now;
fps = lFps;
}
consoleTotal.setContent(poolMetrics.total);
consoleRecycled.setContent(poolMetrics.recycled);
consoleDestroyed.setContent(poolMetrics.destroyed);
consoleInPool.setContent(poolMetrics.inPool);
consoleInUse.setContent(poolMetrics.inUse);
consoleInQueue.setContent(poolMetrics.inQueue);
}
function onSuspend() {
paused = true;
}
function onResume(type, delta) {
var i = 0, particle;
for(; (particle = particles[i]) !== undefined; i++) {
particle.birthtime += delta;
particle.deathtime += delta;
}
paused = false;
}
qWindow.on('resize orientationchange', onResize);
qCanvas.on('touchstart click', addFirework);
renderer.on('tick', onTick);
renderer.on('suspend', onSuspend);
renderer.on('resume', onResume);
initializeSettings();
onResize();
generateRandomFirework();
});
});
});
}(require, window, document));