Popup Celebrations
<canvas id="drawing_canvas"></canvas>
<style>
#drawing_canvas {
position: absolute;
margin: auto;
width: 1200px;
height: 750px;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
<script>
const TWO_PI = Math.PI * 2;
const HALF_PI = Math.PI * 0.5;
// canvas settings
var viewWidth = 1200,
viewHeight = 750,
drawingCanvas = document.getElementById("drawing_canvas"),
ctx,
timeStep = (1 / 60);
Point = function(x, y) {
this.x = x || 0;
this.y = y || 0;
};
Particle = function(p0, p1, p2, p3) {
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
this.time = 0;
this.duration = 3 + Math.random() * 2;
this.color = '#' + Math.floor((Math.random() * 0xffffff)).toString(16);
this.w = 8;
this.h = 6;
this.complete = false;
};
Particle.prototype = {
update: function() {
this.time = Math.min(this.duration, this.time + timeStep);
var f = Ease.outCubic(this.time, 0, 1, this.duration);
var p = cubeBezier(this.p0, this.p1, this.p2, this.p3, f);
var dx = p.x - this.x;
var dy = p.y - this.y;
this.r = Math.atan2(dy, dx) + HALF_PI;
this.sy = Math.sin(Math.PI * f * 10);
this.x = p.x;
this.y = p.y;
this.complete = this.time === this.duration;
},
draw: function() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.r);
ctx.scale(1, this.sy);
ctx.fillStyle = this.color;
ctx.fillRect(-this.w * 0.5, -this.h * 0.5, this.w, this.h);
ctx.restore();
}
};
Loader = function(x, y) {
this.x = x;
this.y = y;
this.r = 24;
this._progress = 0;
this.complete = false;
};
Loader.prototype = {
reset: function() {
this._progress = 0;
this.complete = false;
},
set progress(p) {
this._progress = p < 0 ? 0 : (p > 1 ? 1 : p);
this.complete = this._progress === 1;
},
get progress() {
return this._progress;
},
draw: function() {
ctx.fillStyle = '#dd22aa';
ctx.beginPath();
// ctx.arc(this.x, this.y, this.r, -HALF_PI, TWO_PI * this._progress - HALF_PI);
ctx.lineTo(this.x, this.y);
ctx.closePath();
ctx.fill();
}
};
// pun intended
Exploader = function(x, y) {
this.x = x;
this.y = y;
this.startRadius = 24;
this.time = 0;
this.duration = 0.4;
this.progress = 0;
this.complete = false;
};
Exploader.prototype = {
reset: function() {
this.time = 0;
this.progress = 0;
this.complete = false;
},
update: function() {
this.time = Math.min(this.duration, this.time + timeStep);
this.progress = Ease.inBack(this.time, 0, 1, this.duration);
this.complete = this.time === this.duration;
},
draw: function() {
ctx.fillStyle = '#fff';
ctx.beginPath();
// ctx.arc(this.x, this.y, this.startRadius * (1 - this.progress), 0, TWO_PI);
ctx.fill();
}
};
var particles = [],
loader,
exploader,
phase = 0;
function initDrawingCanvas() {
drawingCanvas.width = viewWidth;
drawingCanvas.height = viewHeight;
ctx = drawingCanvas.getContext('2d');
createLoader();
createExploader();
createParticles();
}
function createLoader() {
loader = new Loader(viewWidth * 0.5, viewHeight * 0.5);
}
function createExploader() {
exploader = new Exploader(viewWidth * 0.5, viewHeight * 0.5);
}
function createParticles() {
for (var i = 0; i < 128; i++) {
var p0 = new Point(viewWidth * 0.5, viewHeight * 0.5);
var p1 = new Point(Math.random() * viewWidth, Math.random() * viewHeight);
var p2 = new Point(Math.random() * viewWidth, Math.random() * viewHeight);
var p3 = new Point(Math.random() * viewWidth, viewHeight + 64);
particles.push(new Particle(p0, p1, p2, p3));
}
}
function update() {
switch (phase) {
case 0:
loader.progress += (1 / 45);
break;
case 1:
exploader.update();
break;
case 2:
particles.forEach(function(p) {
p.update();
});
break;
}
}
function draw() {
ctx.clearRect(0, 0, viewWidth, viewHeight);
switch (phase) {
case 0:
loader.draw();
break;
case 1:
exploader.draw();
break;
case 2:
particles.forEach(function(p) {
p.draw();
});
break;
}
}
window.onload = function() {
initDrawingCanvas();
requestAnimationFrame(loop);
};
function loop() {
update();
draw();
if (phase === 0 && loader.complete) {
phase = 1;
} else if (phase === 1 && exploader.complete) {
phase = 2;
} else if (phase === 2 && checkParticlesComplete()) {
// reset
phase = 0;
loader.reset();
exploader.reset();
particles.length = 0;
createParticles();
}
requestAnimationFrame(loop);
}
function checkParticlesComplete() {
for (var i = 0; i < particles.length; i++) {
if (particles[i].complete === false) return false;
}
return true;
}
// math and stuff
/**
* easing equations from http://gizma.com/easing/
* t = current time
* b = start value
* c = delta value
* d = duration
*/
var Ease = {
inCubic: function(t, b, c, d) {
t /= d;
return c * t * t * t + b;
},
outCubic: function(t, b, c, d) {
t /= d;
t--;
return c * (t * t * t + 1) + b;
},
inOutCubic: function(t, b, c, d) {
t /= d / 2;
if (t < 1) return c / 2 * t * t * t + b;
t -= 2;
return c / 2 * (t * t * t + 2) + b;
},
inBack: function(t, b, c, d, s) {
s = s || 1.70158;
return c * (t /= d) * t * ((s + 1) * t - s) + b;
}
};
function cubeBezier(p0, c0, c1, p1, t) {
var p = new Point();
var nt = (1 - t);
p.x = nt * nt * nt * p0.x + 3 * nt * nt * t * c0.x + 3 * nt * t * t * c1.x + t * t * t * p1.x;
p.y = nt * nt * nt * p0.y + 3 * nt * nt * t * c0.y + 3 * nt * t * t * c1.y + t * t * t * p1.y;
return p;
}
</script>
Comments
Post a Comment