Using this pen from @jackrugile as a guideline (thanks jack :D) http://codepen.io/jackrugile/pen/eJJejX
A Pen by Matei Copot on CodePen.
<canvas id=c></canvas> | |
<p>Calculating and prerendering...</p> |
Using this pen from @jackrugile as a guideline (thanks jack :D) http://codepen.io/jackrugile/pen/eJJejX
A Pen by Matei Copot on CodePen.
var w = c.width = window.innerWidth, | |
h = c.height = window.innerHeight, | |
ctx = c.getContext( '2d' ), | |
opts = { | |
backgroundColor: 'hsl(0,0%,20%)', | |
gradientColors: [ 'hsla(200,80%,60%,.5)', 'hsla(200,80%,30%,.4)', 'hsla(0,0%,30%,0)'], | |
baseLight: 0, | |
addedLight: 100, | |
cx: w / 2, | |
cy: h / 2, | |
pcx: w / 2 - 100, | |
pcy: h / 2, | |
pacRadius: 50, | |
pacTime: 20, | |
pacRadiant: 1, | |
pacColor: 'hsl(40,80%,63%)', | |
pacBlur: 5, | |
foodCount: 5, | |
foodBaseDistance: 20, | |
foodDistance: 300, | |
foodSize: 10, | |
foodColor: 'hsl(180,80%,60%)', | |
foodShadow: 'hsl(220,80%,60%)', | |
foodBlur: 10, | |
text: 'waka', | |
textTime: 20, | |
textColor: 'hsl(40,80%,60%)', | |
baseTempRadiant: 1.1, | |
addedTempRadiant: Math.PI - 1.1 - 1.1, | |
trailX: w / 2 - 100 - 20, | |
trailWidth: 200, | |
trailHeight: 70, | |
trailStrokeWidth: 4, | |
trailColors: [ 'hsla(40,80%,75%,0)', 'hsla(40,80%,75%,.2)' ], | |
trailStrokeColor: 'hsla(40,80%,80%.5)', | |
particles: 40, | |
particleBaseSize: 2, | |
particleAddedSize: 2, | |
particleBaseSpeed: 1.5, | |
particleAddedSpeed: 1.5, | |
particleBaseTime: 40, | |
particleAddedTime: 20, | |
particleColor: 'hsla(50,80%,75%,.8)' | |
}, | |
bgCanvas = document.createElement( 'canvas' ), | |
bgCtx = bgCanvas.getContext( '2d' ), | |
tick = 0, | |
tempText = '', | |
tempTextLength = 0, | |
tempRadiant = Math.PI / 2, | |
tempTime = 0, | |
particles = []; | |
ctx.font = '15px Verdana'; | |
var textBase = -ctx.measureText( opts.text ).width / 2; | |
function init(){ | |
bgCanvas.width = w; | |
bgCanvas.height = h; | |
bgCtx.fillStyle = opts.backgroundColor; | |
bgCtx.fillRect( 0, 0, w, h ); | |
var gradient = bgCtx.createRadialGradient( | |
opts.cx, opts.cy, 0, | |
opts.cx, opts.cy, Math.sqrt( opts.cx*opts.cx + opts.cy*opts.cy ) ); | |
for( var i = 0; i < opts.gradientColors.length; ++i ) | |
gradient.addColorStop( i / opts.gradientColors.length, opts.gradientColors[ i ] ); | |
bgCtx.fillStyle = gradient; | |
bgCtx.fillRect( 0, 0, w, h ); | |
for( var y = 0; y < h; ++y ){ | |
for( var x = 0; x < w; ++x ){ | |
bgCtx.fillStyle = 'hsla(0,0%,light%,.02)'.replace( 'light', ( opts.baseLight + opts.addedLight * Math.random() ) |0 ); | |
bgCtx.fillRect( x, y, 1, 1 ); | |
} | |
bgCtx.fillStyle = y % 2 ? | |
'hsla(0, 0%, 0%, 0.1)' : 'hsla(0, 0%, 100%, 0.05)'; | |
bgCtx.fillRect( 0, y, w, 1 ); | |
} | |
gradient = bgCtx.createLinearGradient( opts.trailX - opts.trailWidth, 0, opts.pcx, 0 ); | |
for( var i = 0; i < opts.trailColors.length; ++i ) | |
gradient.addColorStop( i / opts.trailColors.length, opts.trailColors[ i ] );// | |
bgCtx.fillStyle = gradient; | |
bgCtx.fillRect( opts.trailX - opts.trailWidth, opts.cy - opts.trailHeight / 2, opts.trailWidth, opts.trailHeight ); | |
bgCtx.fillStyle = bgCtx.shadowColor = opts.trailStrokeColor; | |
bgCtx.shadowBlur = 5; | |
bgCtx.beginPath(); | |
bgCtx.moveTo( opts.trailX, opts.cy - opts.trailHeight / 2 - opts.trailStrokeWidth / 2 ); | |
bgCtx.lineTo( opts.trailX, opts.cy - opts.trailHeight / 2 + opts.trailStrokeWidth / 2 ); | |
bgCtx.lineTo( opts.trailX - opts.trailWidth, opts.cy - opts.trailHeight / 2 ); | |
bgCtx.closePath(); | |
bgCtx.moveTo( opts.trailX, opts.cy + opts.trailHeight / 2 - opts.trailStrokeWidth / 2 ); | |
bgCtx.lineTo( opts.trailX, opts.cy + opts.trailHeight / 2 + opts.trailStrokeWidth / 2 ); | |
bgCtx.lineTo( opts.trailX - opts.trailWidth, opts.cy + opts.trailHeight / 2 ); | |
bgCtx.fill(); | |
bgCtx.shadowBlur = 0; | |
anim(); | |
} | |
function anim(){ | |
window.requestAnimationFrame( anim ); | |
ctx.fillStyle = '#222'; | |
ctx.fillRect( 0, 0, w, h ); | |
ctx.drawImage( bgCanvas, 0, 0 ); | |
++tick; | |
drawFood(); | |
drawParticles(); | |
drawPacMan(); | |
} | |
function drawFood(){ | |
ctx.fillStyle = opts.foodColor; | |
ctx.shadowColor = opts.foodShadow; | |
ctx.shadowBlur = opts.foodBlur; | |
var time = tick % opts.pacTime, | |
proportion = time / opts.pacTime, | |
dist = opts.foodDistance / opts.foodCount, | |
addedDist = ( dist + 1 ) * ( 1 - proportion ); | |
if( time === 0 ){ | |
tempRadiant = opts.baseTempRadiant + opts.addedTempRadiant * Math.random(); | |
if( Math.random() < .5 ) | |
tempRadiant *= -1; | |
} | |
for( var i = 0; i < opts.foodCount; ++i ){ | |
var size = i !== opts.foodCount - 1 ? opts.foodSize : opts.foodSize * proportion; | |
ctx.fillRect( opts.pcx - size + dist * i + addedDist + opts.foodBaseDistance, opts.pcy - size, size * 2, size * 2 ); | |
} | |
ctx.shadowBlur = 0; | |
ctx.fillStyle = opts.textColor; | |
if( time < opts.textTime ){ | |
ctx.save(); | |
var scale = time / opts.textTime; | |
if( scale > .5 ) | |
scale = 1 - scale; | |
scale *= 2; | |
if( tempRadiant > 0 ){ | |
ctx.translate( opts.pcx, opts.pcy ); | |
ctx.rotate( tempRadiant ); | |
ctx.translate( opts.pacRadius + 15, 0 ); | |
ctx.rotate( -Math.PI / 2 ); | |
ctx.scale( scale, scale ); | |
ctx.fillText( opts.text, textBase, 0 ); | |
} else { | |
ctx.translate( opts.pcx, opts.pcy ); | |
ctx.rotate( tempRadiant ); | |
ctx.translate( opts.pacRadius + 5, 0 ); | |
ctx.rotate( Math.PI / 2 ); | |
ctx.scale( scale, scale ); | |
ctx.fillText( opts.text, textBase, 0 ); | |
} | |
ctx.restore(); | |
} | |
} | |
function drawParticles(){ | |
if( particles.length < opts.particles && Math.random() < .1 ) | |
particles.push( new Particle ); | |
ctx.fillStyle = ctx.shadowColor = opts.particleColor; | |
ctx.shadowBlur = 4; | |
ctx.beginPath(); | |
ctx.translate( opts.trailX, opts.cy - opts.trailHeight / 2 ); | |
particles.map( function( particle ){ particle.step(); } ); | |
ctx.translate( -opts.trailX, -( opts.cy - opts.trailHeight / 2 ) ); | |
ctx.fill(); | |
} | |
function Particle(){ | |
this.reset(); | |
} | |
Particle.prototype.reset = function(){ | |
this.x = 0; | |
this.y = Math.random() * opts.trailHeight; | |
this.speed = opts.particleBaseSpeed + opts.particleAddedSpeed * Math.random(); | |
this.vy = ( Math.random() - .5 ) * 2; | |
this.tick = 0; | |
this.time = ( opts.particleBaseTime + opts.particleAddedTime * Math.random() ) |0; | |
this.size = ( opts.particleBaseSize + opts.particleAddedSize * Math.random() ) |0; | |
} | |
Particle.prototype.step = function(){ | |
++this.tick; | |
var size = ( 1 - this.tick / this.time ) * this.size; | |
this.x -= this.speed; | |
this.y += this.vy + ( Math.random() -.5 ) * 2; | |
ctx.moveTo( this.x + size, this.y ); | |
ctx.arc( this.x, this.y, size, 0, Math.PI * 2 ); | |
if( this.tick >= this.time ) | |
this.reset(); | |
} | |
function drawPacMan(){ | |
ctx.fillStyle = ctx.shadowColor = opts.pacColor; | |
ctx.shadowBlur = opts.pacBlur; | |
var proportion = -Math.cos( tick / opts.pacTime * 2 * Math.PI ) / 2 + .5; | |
ctx.beginPath(); | |
ctx.moveTo( opts.pcx, opts.pcy ); | |
ctx.arc( opts.pcx, opts.pcy, opts.pacRadius, opts.pacRadiant * proportion, Math.PI * 2 - opts.pacRadiant * proportion ); | |
ctx.fill(); | |
ctx.shadowBlur = 0; | |
} | |
init(); | |
//anim(); |
body { | |
background-color: #222; | |
} | |
canvas { | |
position: absolute; | |
top: 0; | |
left: 0; | |
} | |
canvas#c { | |
z-index: 2; | |
} | |
p { | |
position: absolute; | |
width: 100%; | |
height: 40px; | |
top: calc( 50% - 20px ); | |
left: 0; | |
text-align: center; | |
font: 30px Verdana; | |
color: #eee; | |
text-shadow: 0 0 1px #888; | |
} |