Created
February 11, 2013 23:44
-
-
Save baumicon/4758705 to your computer and use it in GitHub Desktop.
A CodePen by Michael. Kira Kira Particle
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
<canvas id='c'></canvas> |
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
/** | |
* requestAnimationFrame | |
*/ | |
window.requestAnimationFrame = (function(){ | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimationFrame || | |
function (callback) { window.setTimeout(callback, 1000 / 60); }; | |
})(); | |
/** | |
* Twinkle | |
*/ | |
var Twinkle = (function() { | |
// Config | |
var STAR_VERTEX_NUMS = [4, 6, 8, 10, 12], | |
MAX_STAR_NUM = 2500; | |
/** | |
* @constructor | |
*/ | |
function Twinkle(starColor, starRadius, starBlur) { | |
this.initSymbols(starColor, starRadius, starBlur); | |
this.particles = []; | |
this._pool = []; | |
this.mouse = new Mouse(); | |
} | |
Twinkle.prototype = { | |
mouse: null, | |
gravity: 0.035, | |
initSymbols: function(color, radius, blur) { | |
this._symbols = new Symbols(color, radius, blur); | |
}, | |
render: function(ctx) { | |
var particles = this.particles, | |
mouse = this.mouse, | |
gravity = this.gravity, | |
speedRatio, | |
magMax, | |
magMin, | |
scaleMax, | |
symbols = this._symbols, | |
symbolNum = this._symbols.length, | |
symbol, | |
size = this._symbols.size, | |
radius = this._symbols.size * 0.5, | |
drawSize, | |
drawSizeHalf, | |
drawScale, | |
canvasWidth = ctx.canvas.width, | |
canvasHeight = ctx.canvas.height, | |
i, len, p; | |
speedRatio = Math.min((mouse.speedX * mouse.speedX + mouse.speedY * mouse.speedY) * 0.05, 1); | |
if (particles.length < MAX_STAR_NUM) { | |
magMax = 0.5 + 4.5 * speedRatio; | |
magMin = 0.1 + 0.5 * speedRatio; | |
scaleMax = 0.5 + 0.5 * speedRatio; | |
len = (3 * Math.random() | 0) + (50 * speedRatio | 0); | |
for (i = 0; i < len; i++) this._createParticle(magMin, magMax, scaleMax); | |
} | |
for (i = 0, len = particles.length; i < len; i++) { | |
p = particles[i]; | |
p.vx += mouse.speedX * speedRatio * 0.3; | |
p.vy += mouse.speedY * speedRatio * 0.3 + gravity; | |
p.x += p.vx; | |
p.y += p.vy; | |
p.scale -= 0.0025; | |
p.angle += Math.random(); | |
if ( | |
p.x + radius < 0 || | |
p.x - radius > canvasWidth || | |
p.y + radius < 0 || | |
p.y - radius > canvasHeight || | |
p.radius <= 0 | |
) { | |
this._pool.push(p); | |
particles.splice(i, 1); | |
len--; | |
i--; | |
continue; | |
} | |
drawScale = p.scale; | |
symbol = symbols[symbolNum * Math.random() | 0]; | |
if (Math.random() < 0.7) drawScale *= 0.2; | |
drawSize = size * drawScale; | |
drawSizeHalf = drawSize * 0.5; | |
ctx.save(); | |
ctx.globalCompositeOperation = 'lighter'; | |
ctx.translate(p.x, p.y); | |
ctx.rotate(p.angle); | |
ctx.drawImage(symbol, 0, 0, size, size, -drawSizeHalf, -drawSizeHalf, drawSize, drawSize); | |
ctx.restore(); | |
} | |
ctx.fill(); | |
mouse.speedX = mouse.speedY = 0; | |
}, | |
_createParticle: function(magMin, magMax, scaleMax) { | |
var mag = magMin + (magMax - magMin) * Math.random(), | |
angle = Math.PI * 2 * Math.random(), | |
p = this._pool.length ? this._pool.shift() : new Particle(); | |
p.init( | |
this.mouse.x, | |
this.mouse.y, | |
mag * Math.cos(angle), | |
mag * Math.sin(angle), | |
scaleMax * Math.random(), | |
Math.PI * 2 * Math.random() | |
); | |
this.particles.push(p); | |
} | |
}; | |
/** | |
* Mouse | |
* @private | |
*/ | |
function Mouse(x, y) { | |
this.x = x || 0; | |
this.y = y || 0; | |
} | |
Mouse.prototype = { | |
x: 0, | |
y: 0, | |
speedX: 0, | |
speedY: 0, | |
update: function(x, y) { | |
this.speedX = (this.x - x) * 0.3333; | |
this.speedY = (this.y - y) * 0.3333; | |
this.x = x; | |
this.y = y; | |
} | |
}; | |
/** | |
* Symbols | |
* @see STAR_VERTEX_NUMS | |
* @private | |
*/ | |
function Symbols(color, radius, blur) { | |
this.color = parseColor(color); | |
this.size = (radius + blur) * 2; | |
for (var i = 0, len = STAR_VERTEX_NUMS.length; i < len; i++) { | |
this.push(this._createSymbol(STAR_VERTEX_NUMS[i], radius, blur)); | |
} | |
} | |
Symbols.prototype = []; | |
Symbols.prototype._createSymbol = function(vertexNum, radius, blur) { | |
var canvas, | |
context, | |
size = this.size, | |
center = this.size / 2, | |
color = this.color; | |
canvas = document.createElement('canvas'); | |
canvas.width = canvas.height = size; | |
context = canvas.getContext('2d'); | |
context.fillStyle = colorToString(color[0], color[1], color[2], color[3], color[4]); | |
context.shadowBlur = blur; | |
context.shadowColor = colorToString(color[0], color[1], color[2], color[3], color[4] * 0.75); | |
var i, len, r, a; | |
context.beginPath(); | |
for (i = 1, len = vertexNum * 2; i <= len; i++) { | |
r = i % 2 ? radius * 0.1 : radius; | |
a = Math.PI * 2 * i / len; | |
context[i === 1 ? 'moveTo' : 'lineTo'](center + r * Math.cos(a), center + r * Math.sin(a)); | |
} | |
context.fill(); | |
return canvas; | |
}; | |
/** | |
* Particle | |
* @private | |
*/ | |
function Particle(x, y, vx, vy, scale, angle) { | |
this.init(x, y, vx, vy, scale, angle); | |
} | |
Particle.prototype.init = function(x, y, vx, vy, scale, angle) { | |
this.x = x || 0; | |
this.y = y || 0; | |
this.vx = vx || 0; | |
this.vy = vy || 0; | |
this.scale = scale || 0; | |
this.angle = angle || 0; | |
}; | |
// Helpers | |
var parseColor = (function() { | |
var RE_RGB = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/, | |
RE_RGBA = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)$/, | |
RE_HSL = /^hsl\(\s*([\d\.]+)\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)%\s*\)$/, | |
RE_HSLA = /^hsla\(\s*([\d\.]+)\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)\s*\)$/, | |
RE_HEX = /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/; // 6 digit | |
return function(str) { | |
str = str.replace(/^\s*#|\s*$/g, ''); | |
str = str.toLowerCase(); | |
var match; | |
// RGB(A) | |
if ((match = str.match(RE_RGB) || str.match(RE_RGBA))) { | |
return [ | |
'rgba', | |
parseInt(match[1], 10), | |
parseInt(match[2], 10), | |
parseInt(match[3], 10), | |
parseFloat(match.length === 4 ? 1 : match[4]) | |
]; | |
} | |
// HSL(A) | |
if ((match = str.match(RE_HSL) || str.match(RE_HSLA))) { | |
return [ | |
'hsla', | |
parseFloat(match[1]), | |
parseFloat(match[2]), | |
parseFloat(match[3]), | |
parseFloat(match.length === 4 ? 1 : match[4]) | |
]; | |
} | |
// Hex | |
if (str.length === 3) { | |
// Hex 3 digit -> 6 digit | |
str = str.replace(/(.)/g, '$1$1'); | |
} | |
if ((match = str.match(RE_HEX))) { | |
return [ | |
'rgba', | |
parseInt(match[1], 16), | |
parseInt(match[2], 16), | |
parseInt(match[3], 16), | |
1 | |
]; | |
} | |
return null; | |
}; | |
})(); | |
function colorToString(type, v0, v1, v2, a) { | |
if (type === 'rgba') return 'rgba(' + v0 + ',' + v1 + ',' + v2 + ',' + a + ')'; | |
if (type === 'hsla') return 'hsla(' + v0 + ',' + v1 + '%,' + v2 + '%,' + a + ')'; | |
else return ''; | |
} | |
return Twinkle; | |
})(); | |
// Initialize | |
(function() { | |
// Configs | |
var Configs = { | |
backgroundColor: '#1B1917', | |
starColor: '#FFFFFF', | |
starRadius: 12, | |
starBlur: 4 | |
}; | |
// *:;;:*: Merry Christmas *:;;:* | |
if (new Date().getMonth() === 11) { | |
Configs.backgroundColor = '#8C1010'; | |
Configs.starColor = '#FAF8EB'; | |
} | |
// Vars | |
var canvas, | |
context, | |
canvasBound, | |
grad, | |
twinkle, | |
autoPos = { tx: 0, ty: 0, x: 0, y: 0, vx: 0, vy: 0, enable: true }, | |
gui, | |
timeoutId; | |
// Initialize | |
function init() { | |
canvas = document.getElementById('c'); | |
context = canvas.getContext('2d'); | |
onWindowResize(null); | |
twinkle = new Twinkle(Configs.starColor, Configs.starRadius, Configs.starBlur); | |
window.addEventListener('resize', onWindowResize, false); | |
canvas.addEventListener('mousemove', onCanvasMouseMove, false); | |
canvas.addEventListener('mouseout', onCanvasMouseOut, false); | |
gui = new dat.GUI(); | |
gui.addColor(Configs, 'backgroundColor').name('Background'); | |
gui.addColor(Configs, 'starColor').name('Star Color').onChange(onGUISymbolSettingChange); | |
gui.add(Configs, 'starRadius', 1, 30).name('Star Radius').step(1).onChange(onGUISymbolSettingChange); | |
gui.add(Configs, 'starBlur', 0, 16).name('Star Blur').step(1).onChange(onGUISymbolSettingChange); | |
gui.close(); | |
update(); | |
} | |
// Event listeners | |
function onWindowResize(e) { | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
canvasBound = canvas.getBoundingClientRect(); | |
var cx = canvas.width * 0.5, | |
cy = canvas.height * 0.5; | |
grad = context.createRadialGradient(cx, cy, 0, cx, cy, Math.sqrt(cx * cx + cy * cy)); | |
grad.addColorStop(0, 'rgba(0, 0, 0, 0)'); | |
grad.addColorStop(1, 'rgba(0, 0, 0, 0.25)'); | |
} | |
function onCanvasMouseMove(e) { | |
twinkle.mouse.update(e.clientX - canvasBound.left, e.clientY - canvasBound.top); | |
autoPos.enable = false; | |
} | |
function onCanvasMouseOut(e) { | |
} | |
function onGUISymbolSettingChange() { | |
if (timeoutId) clearTimeout(timeoutId); | |
timeoutId = setTimeout(function() { | |
twinkle.initSymbols(Configs.starColor, Configs.starRadius, Configs.starBlur); | |
}, 300); | |
} | |
// Update | |
function update() { | |
context.fillStyle = Configs.backgroundColor; | |
context.fillRect(0, 0, canvas.width, canvas.height); | |
context.fillStyle = grad; | |
context.fillRect(0, 0, canvas.width, canvas.height); | |
twinkle.render(context); | |
requestAnimationFrame(update); | |
} | |
// Run | |
init(); | |
})(); |
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
body { | |
padding: 0; | |
margin: 0; | |
font: 12px sans-serif; | |
background-color: #000; | |
overflow: hidden; | |
} | |
canvas { | |
position: absolute; | |
top: 0; | |
left: 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment