Initial commit
BIN
assets/cannon-2.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/cannon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/icons/Airport-icon.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
assets/icons/Beer-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Bicep-icon.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/icons/Bike-icon.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/icons/Birthday-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Bloody-Mary-icon.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/icons/Book-icon.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/icons/Brunch-icon.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/icons/Candy-Cane-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Cat-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Chicken-Leg-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Chinese-Take-Out-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/Christmas-Tree-icon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/icons/Clapper-icon.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/icons/Coffee-2-icon.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
assets/icons/Coffee-icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/icons/Cosmo-icon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/icons/Croissant-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Dog-icon.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/icons/Dreidel-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Fast-Food-icon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/icons/Fire-icon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/icons/Fork-Knife-icon.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/icons/Gameboy-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Guacamole-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Guitar-icon.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/icons/Hair-icon.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/icons/Heart-icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/icons/Hot-Dog-icon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/icons/Hungry-icon.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
assets/icons/Ice-Cream-icon.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
assets/icons/Juice-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/Kebab-icon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/icons/Laptop-icon.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
assets/icons/Lipstick-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Mayor-Airport-icon.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
assets/icons/Mayor-Beer-icon.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/icons/Mayor-Book-icon.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/icons/Mayor-Brunch-icon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/icons/Mayor-Clapper-icon.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/icons/Mayor-Coffee-icon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/icons/Mayor-Croissant-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/Mayor-Fast-Food-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Mayor-Foam-Hand-icon.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
assets/icons/Mayor-Fork-Knife-icon.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
assets/icons/Mayor-Gym-icon.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/icons/Mayor-Hair-icon.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/icons/Mayor-Ice-Cream-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Mayor-Lap-Top-icon.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
assets/icons/Mayor-Music-icon.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/icons/Mayor-Park-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Mayor-Pizza-icon.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
assets/icons/Mayor-Shopping-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Mayor-Suitcase-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/Mayor-Sunglasses-icon.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/icons/Mayor-Surfer-icon.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
assets/icons/Mayor-Ticket-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Mayor-Underpants-icon.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/icons/Mayor-Whiskey-icon.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
assets/icons/Mayor-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Microphone-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/Mona-Lisa-icon.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/icons/Music-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Nerd-Glasses-icon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/icons/New-Year-icon.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
assets/icons/Office-Stappler-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Park-icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/icons/Party-Hat-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Pie-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Pizza-icon.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/icons/Poop-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Rain-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Running-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Sandwhich-icon.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/icons/Shopping-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Skateboard-icon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/icons/Sofa-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Space-Shuttle-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Suitcase-icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/icons/Sunglasses-icon.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/icons/Sunshine-icon.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/icons/Superuser-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/Surfer-icon.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/icons/Sushi-icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/icons/Tako-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Ticket-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/icons/Turkey-icon.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/icons/Underpants-icon.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/icons/Unicorn-icon.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/icons/Whiskey-icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/icons/Wine-icon.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
assets/icons/Zzz-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/icons/gym-icon.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/icons/hanukkah-icon.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
assets/icons/ivoted-2014-icon.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
355
confetti.js
Normal file
@@ -0,0 +1,355 @@
|
||||
// utilities
|
||||
function getLength(x0, y0, x1, y1) {
|
||||
// returns the length of a line segment
|
||||
const x = x1 - x0;
|
||||
const y = y1 - y0;
|
||||
return Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
function getDegAngle(x0, y0, x1, y1) {
|
||||
const y = y1 - y0;
|
||||
const x = x1 - x0;
|
||||
return Math.atan2(y, x) * (180 / Math.PI);
|
||||
}
|
||||
|
||||
// some constants
|
||||
const DECAY = 4; // confetti decay in seconds
|
||||
const SPREAD = 30*3.141592/180; // degrees to spread from the angle of the cannon
|
||||
const GRAVITY = 120;
|
||||
|
||||
class ConfettiCannon {
|
||||
constructor() {
|
||||
// setup a canvas
|
||||
this.canvas = document.getElementById('canvas');
|
||||
this.dpr = window.devicePixelRatio || 1;
|
||||
this.ctx = this.canvas.getContext('2d');
|
||||
this.ctx.scale(this.dpr, this.dpr);
|
||||
|
||||
// add confetti here
|
||||
this.confettiSpriteIds = [];
|
||||
this.confettiSprites = {};
|
||||
|
||||
// vector line representing the firing angle
|
||||
this.drawVector = false;
|
||||
this.vector = [{
|
||||
x: window.innerWidth * 0.9,
|
||||
y: window.innerHeight * 0.8,
|
||||
}, {
|
||||
x: window.innerWidth,
|
||||
y: window.innerHeight,
|
||||
}];
|
||||
|
||||
this.pointer = {};
|
||||
|
||||
// bind methods
|
||||
this.render = this.render.bind(this);
|
||||
this.handleMousedown = this.handleMousedown.bind(this);
|
||||
this.handleMouseup = this.handleMouseup.bind(this);
|
||||
this.handleMousemove = this.handleMousemove.bind(this);
|
||||
this.handleTouchstart = this.handleTouchstart.bind(this);
|
||||
this.handleTouchmove = this.handleTouchmove.bind(this);
|
||||
this.setCanvasSize = this.setCanvasSize.bind(this);
|
||||
|
||||
this.setupListeners();
|
||||
this.setCanvasSize();
|
||||
|
||||
// fire off for a demo
|
||||
//this.timer = setTimeout(this.handleMouseup, 1000);
|
||||
}
|
||||
|
||||
setupListeners() {
|
||||
// Use TweenLite tick event for the render loop
|
||||
TweenLite.ticker.addEventListener('tick', this.render);
|
||||
|
||||
// bind events
|
||||
window.addEventListener('mousedown', this.handleMousedown);
|
||||
window.addEventListener('mouseup', this.handleMouseup);
|
||||
window.addEventListener('mousemove', this.handleMousemove);
|
||||
window.addEventListener('touchstart', this.handleTouchstart);
|
||||
window.addEventListener('touchend', this.handleMouseup);
|
||||
window.addEventListener('touchmove', this.handleTouchmove);
|
||||
window.addEventListener('resize', this.setCanvasSize);
|
||||
}
|
||||
|
||||
setCanvasSize() {
|
||||
this.canvas.width = window.innerWidth * this.dpr;
|
||||
this.canvas.height = window.innerHeight * this.dpr;
|
||||
this.canvas.style.width = window.innerWidth + 'px';
|
||||
this.canvas.style.height = window.innerHeight + 'px';
|
||||
}
|
||||
|
||||
handleMousedown(event) {
|
||||
clearTimeout(this.timer);
|
||||
const x = event.clientX * this.dpr;
|
||||
const y = event.clientY * this.dpr;
|
||||
|
||||
this.vector[0] = {
|
||||
x,
|
||||
y,
|
||||
};
|
||||
this.drawVector = true;
|
||||
}
|
||||
|
||||
handleTouchstart(event) {
|
||||
clearTimeout(this.timer);
|
||||
event.preventDefault();
|
||||
const x = event.touches[0].clientX * this.dpr;
|
||||
const y = event.touches[0].clientY * this.dpr;
|
||||
this.vector[0] = {
|
||||
x,
|
||||
y,
|
||||
};
|
||||
|
||||
this.drawVector = true;
|
||||
}
|
||||
|
||||
handleMouseup(event) {
|
||||
this.drawVector = false;
|
||||
|
||||
const x0 = this.vector[0].x;
|
||||
const y0 = this.vector[0].y;
|
||||
const x1 = this.vector[1].x;
|
||||
const y1 = this.vector[1].y;
|
||||
|
||||
const length = getLength(x0, y0, x1, y1);
|
||||
const angle = (getDegAngle(x0, y0, x1, y1) - 180)*-3.141592/180;
|
||||
|
||||
const particles = length / 3 + 5;
|
||||
const velocity = length * 50;
|
||||
this.addConfettiParticles(particles, angle, velocity, x0, y0);
|
||||
}
|
||||
|
||||
handleMousemove(event) {
|
||||
const x = event.clientX * this.dpr;
|
||||
const y = event.clientY * this.dpr;
|
||||
this.vector[1] = {
|
||||
x,
|
||||
y,
|
||||
};
|
||||
this.pointer = this.vector[1];
|
||||
}
|
||||
|
||||
handleTouchmove(event) {
|
||||
event.preventDefault();
|
||||
const x = event.changedTouches[0].clientX * this.dpr;
|
||||
const y = event.changedTouches[0].clientY * this.dpr;
|
||||
this.vector[1] = {
|
||||
x,
|
||||
y,
|
||||
};
|
||||
this.pointer = this.vector[1];
|
||||
}
|
||||
|
||||
drawVectorLine() {
|
||||
this.ctx.strokeStyle = 'pink';
|
||||
this.ctx.lineWidth = 2 * this.dpr;
|
||||
|
||||
const x0 = this.vector[0].x;
|
||||
const y0 = this.vector[0].y;
|
||||
const x1 = this.vector[1].x;
|
||||
const y1 = this.vector[1].y;
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(x0, y0);
|
||||
this.ctx.lineTo(x1, y1);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
addConfettiParticles(amount, angleP, velocityP, x, y) {
|
||||
let i = 0;
|
||||
while (i < amount) {
|
||||
// sprite
|
||||
const r = _.random(4, 6) * this.dpr;
|
||||
const d = _.random(15, 25) * this.dpr;
|
||||
|
||||
const cr = _.random(30, 255);
|
||||
const cg = _.random(30, 230);
|
||||
const cb = _.random(30, 230);
|
||||
const color = `rgb(${cr}, ${cg}, ${cb})`;
|
||||
|
||||
const tilt = _.random(10, -10);
|
||||
const tiltAngleIncremental = _.random(0.07, 0.05);
|
||||
const tiltAngle = 0;
|
||||
|
||||
const id = _.uniqueId();
|
||||
|
||||
const friction = _.random(0.10, 0.25);
|
||||
|
||||
|
||||
|
||||
const minAngle = angleP - SPREAD / 2;
|
||||
const maxAngle = angleP + SPREAD / 2;
|
||||
const minVelocity = velocityP / 2;
|
||||
const maxVelocity = velocityP;
|
||||
// Physics Props
|
||||
const velocity = _.random(minVelocity, maxVelocity);
|
||||
const angle = _.random(minAngle, maxAngle);
|
||||
|
||||
|
||||
|
||||
const sprite = {
|
||||
[id]: {
|
||||
angle,
|
||||
velocity,
|
||||
x,
|
||||
y,
|
||||
r,
|
||||
d,
|
||||
color,
|
||||
tilt,
|
||||
tiltAngleIncremental,
|
||||
tiltAngle,
|
||||
friction
|
||||
},
|
||||
};
|
||||
|
||||
Object.assign(this.confettiSprites, sprite);
|
||||
this.confettiSpriteIds.push(id);
|
||||
//this.tweenConfettiParticle(id);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
tweenConfettiParticle(id) {
|
||||
const minAngle = this.confettiSprites[id].angle - SPREAD / 2;
|
||||
const maxAngle = this.confettiSprites[id].angle + SPREAD / 2;
|
||||
|
||||
const minVelocity = this.confettiSprites[id].velocity / 4;
|
||||
const maxVelocity = this.confettiSprites[id].velocity;
|
||||
|
||||
// Physics Props
|
||||
const velocity = _.random(minVelocity, maxVelocity);
|
||||
const angle = _.random(minAngle, maxAngle);
|
||||
const gravity = GRAVITY;
|
||||
const friction = _.random(0.01, 0.025);
|
||||
const d = 0;
|
||||
|
||||
/*TweenLite.to(this.confettiSprites[id], DECAY, {
|
||||
physics2D: {
|
||||
velocity,
|
||||
angle,
|
||||
gravity,
|
||||
friction,
|
||||
},
|
||||
d,
|
||||
ease: Power4.easeIn,
|
||||
onComplete: () => {
|
||||
// remove confetti sprite and id
|
||||
_.pull(this.confettiSpriteIds, id);
|
||||
delete this.confettiSprites[id];
|
||||
},
|
||||
});*/
|
||||
}
|
||||
|
||||
updateConfettiParticle(id) {
|
||||
|
||||
const sprite = this.confettiSprites[id];
|
||||
|
||||
const tiltAngle = 0.0005 * sprite.d;
|
||||
|
||||
//sprite.angle -= 0.01;
|
||||
var vx = Math.cos(sprite.angle)*sprite.velocity;
|
||||
var vy = -Math.sin(sprite.angle)*sprite.velocity;
|
||||
vx = Math.sign(vx)*Math.max(0, Math.abs(vx) - sprite.friction);
|
||||
vy = vy + GRAVITY - sprite.friction;
|
||||
sprite.angle = Math.atan2(-vy, vx);
|
||||
|
||||
sprite.tiltAngle += tiltAngle;
|
||||
sprite.tiltAngle += sprite.tiltAngleIncremental;
|
||||
sprite.tilt = (Math.sin(sprite.tiltAngle - (sprite.r / 2))) * sprite.r * 2;
|
||||
sprite.y += vy*0.002+Math.sin(sprite.r / 2);//+Math.sin(sprite.angle + sprite.r / 2);
|
||||
sprite.x += vx*0.002;//Math.cos(sprite.angle) * 2;
|
||||
}
|
||||
|
||||
drawConfetti() {
|
||||
var deletable = [];
|
||||
this.confettiSpriteIds.map(id => {
|
||||
const sprite = this.confettiSprites[id];
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.lineWidth = sprite.d / 2;
|
||||
this.ctx.strokeStyle = sprite.color;
|
||||
this.ctx.moveTo(sprite.x + sprite.tilt + sprite.r, sprite.y);
|
||||
this.ctx.lineTo(sprite.x + sprite.tilt, sprite.y + sprite.tilt + sprite.r);
|
||||
this.ctx.stroke();
|
||||
|
||||
this.updateConfettiParticle(id);
|
||||
});
|
||||
}
|
||||
|
||||
drawPointer() {
|
||||
const centerX = this.pointer.x;
|
||||
const centerY = this.pointer.y;
|
||||
const radius = 15 * this.dpr;
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
|
||||
this.ctx.fillStyle = 'transparent';
|
||||
this.ctx.fill();
|
||||
this.ctx.lineWidth = 2 * this.dpr;
|
||||
this.ctx.strokeStyle = '#ffffff';
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
drawPower() {
|
||||
const x0 = this.vector[0].x;
|
||||
const y0 = this.vector[0].y;
|
||||
const x1 = this.vector[1].x;
|
||||
const y1 = this.vector[1].y;
|
||||
|
||||
const length = getLength(x0, y0, x1, y1);
|
||||
const centerX = x0;
|
||||
const centerY = y0;
|
||||
const radius = 1 * this.dpr * length / 20;
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
|
||||
this.ctx.fillStyle = 'transparent';
|
||||
this.ctx.fill();
|
||||
this.ctx.lineWidth = 2 * this.dpr;
|
||||
this.ctx.strokeStyle = '#333333';
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
// only draw the vector when the drawVector flag is on
|
||||
this.drawVector && this.drawVectorLine();
|
||||
this.drawVector && this.drawPower();
|
||||
|
||||
this.drawPointer();
|
||||
this.drawConfetti();
|
||||
}
|
||||
|
||||
fire(x1, y1, x2, y2) {
|
||||
this.vector = [{
|
||||
x: x1,
|
||||
y: y1,
|
||||
}, {
|
||||
x: x2,
|
||||
y: y2,
|
||||
}];
|
||||
this.handleMouseup();
|
||||
}
|
||||
}
|
||||
var isMobile = false; //initiate as false
|
||||
// device detection
|
||||
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|
||||
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) isMobile = true;
|
||||
|
||||
if (!isMobile) {
|
||||
const confetti = new ConfettiCannon();
|
||||
setTimeout(() => {
|
||||
confetti.fire(window.innerWidth * 0.9, window.innerHeight * 0.8, window.innerWidth, window.innerHeight);
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
confetti.fire(window.innerWidth * 0.1, window.innerHeight * 0.8, 0, window.innerHeight);
|
||||
}, 1050);
|
||||
setTimeout(() => {
|
||||
confetti.fire(window.innerWidth * 0.9, window.innerHeight * 0.8, window.innerWidth, window.innerHeight);
|
||||
}, 2000);
|
||||
setTimeout(() => {
|
||||
confetti.fire(window.innerWidth * 0.1, window.innerHeight * 0.8, 0, window.innerHeight);
|
||||
}, 2050);
|
||||
}
|
||||
20
index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Geburtstag</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.5/TweenLite.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
|
||||
<script type="text/javascript" src="confetti.js" defer></script>
|
||||
<script type="text/javascript" src="text.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
<div id="circle"><div id="inner-circle"></div></div>
|
||||
<div id="number">22</div>
|
||||
<div id="text" style="visibility: hidden;">Happy Börthday!<br><br>Alles Gute zum Purzeltag, lass dich schön von allen feiern, vor allem am Samstag! erstmal die langweiligen Sachen: Viel Erfolg auch weiterhin bei BIO, dass du auch ne Menge Spaß dabei hast, dass das mit der Wohnung und dem Umzug ohne Tote und Armbrüche abläuft und dass alle Träume in Erfüllung gehen. Bleib weiter so fit, genieß deine Freizeit und hab Spaß — Beim Jenieeeeßen macht dir eh keiner was vor.<br><br>Und weil ich zu faul wahr mir eigene Glückwünsche ausudenken, habe ich mir einfach welche aus dem Internet kopiert:<br>Du bist nicht nur ein wahrer Freund, sondern wie <s>ein Sohn</s> eine Freundin für mich. Schon immer gewesen. Ich wünsche dir zum 22. Geburtstag und für das kommende Jahr alles Glück und liebe Grüße von <s>der ganzen Familie</s> mir. #lame<br><br>Alles Liebe!<br><img id="cat" src="assets/icons/Cat-icon.png"></div>
|
||||
</body>
|
||||
<img id="cannon-left" src="assets/cannon-2.png">
|
||||
<img id="cannon-right" src="assets/cannon-2.png">
|
||||
</html>
|
||||
118
style.css
Normal file
@@ -0,0 +1,118 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Love+Ya+Like+A+Sister|Lobster');
|
||||
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #7B7AF2;
|
||||
font-family: 'Lobster', cursive;
|
||||
cursor: pointer;
|
||||
|
||||
overflow: hidden;
|
||||
right: -20px; /* Increase/Decrease this value for cross-browser compatibility */
|
||||
overflow-y: auto;
|
||||
margin-top: -3vmin;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
}
|
||||
|
||||
#number {
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
user-select: none; /* Likely future */
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
height: 60vh;
|
||||
width: 100%;
|
||||
margin-top:-37vh; /* -1/2 height */
|
||||
font-size: 60vh;
|
||||
color: #09093D;
|
||||
|
||||
text-align: center;
|
||||
|
||||
-webkit-text-shadow: 0px 13px 32px rgba(0,0,0,0.3);
|
||||
-moz-text-shadow: 0px 13px 32px rgba(0,0,0,0.3);
|
||||
text-shadow: 0px 13px 32px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
#text {
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
user-select: none; /* Likely future */
|
||||
|
||||
position: absolute;
|
||||
top: 10vmin;
|
||||
height: 60vh;
|
||||
max-width: 60vw;
|
||||
margin-left: 20vw;
|
||||
font-size: 1.3em;
|
||||
color: #09093D/*#e0550c#F4702B*/;
|
||||
|
||||
text-align: center;
|
||||
|
||||
-webkit-text-shadow: 0px 13px 32px rgba(0,0,0,0.5);
|
||||
-moz-text-shadow: 0px 13px 32px rgba(0,0,0,0.5);
|
||||
text-shadow: 0px 13px 32px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
#circle {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
height: 60vh;
|
||||
width: 100%;
|
||||
margin-top:-30vh; /* -1/2 height */
|
||||
font-size: 60vh;
|
||||
color: #09093D;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#inner-circle {
|
||||
display: inline-block;
|
||||
top: 50%;
|
||||
height: 15vh;
|
||||
width: 70vh;
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
border-radius: 50%;
|
||||
|
||||
text-align: center;
|
||||
|
||||
-webkit-box-shadow: 0px 13px 32px rgba(0,0,0,0.3);
|
||||
-moz-box-shadow: 0px 13px 32px rgba(0,0,0,0.3);
|
||||
box-shadow: 0px 13px 32px rgba(0,0,0,0.3);
|
||||
}
|
||||
#cannon-left, #cannon-right {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
max-height: 20vmin;
|
||||
width: auto;
|
||||
margin-bottom: -7vmin;
|
||||
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
user-select: none; /* Likely future */
|
||||
}
|
||||
|
||||
#cannon-left {
|
||||
left: 0;
|
||||
transform: rotate(-45deg);
|
||||
margin-left: -1vmin;
|
||||
}
|
||||
|
||||
#cannon-right {
|
||||
right: 0;
|
||||
transform: rotate(45deg) rotateY(180deg);
|
||||
margin-right: -1vmin;
|
||||
}
|
||||
|
||||
#cat {
|
||||
margin-left: 0 0 0 auto;
|
||||
transform: scale(0.6) rotate(20deg) rotateY(180deg);
|
||||
}
|
||||