Created
December 12, 2018 17:23
-
-
Save pketh/935bb8347652261effcca22e82ce7640 to your computer and use it in GitHub Desktop.
confetti pours on you after you buy something in glitch/hyperweb
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
/* | |
* decaffeinate suggestions: | |
* DS102: Remove unnecessary code created because of implicit returns | |
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md | |
*/ | |
"use strict"; | |
/* istanbul ignore next */ | |
module.exports = function(canvas) { | |
const { PI } = Math; | |
const { sqrt } = Math; | |
const { round } = Math; | |
const { random } = Math; | |
const { cos } = Math; | |
const { sin } = Math; | |
const rAF = window.requestAnimationFrame; | |
const cAF = window.cancelAnimationFrame || window.cancelRequestAnimationFrame; | |
const _now = Date.now; | |
const speed = 50; | |
const duration = 1.0 / speed; | |
const confettiRibbonCount = 11; | |
const ribbonPaperCount = 30; | |
const ribbonPaperDist = 8.0; | |
const ribbonPaperThick = 8.0; | |
const confettiPaperCount = 95; | |
const DEG_TO_RAD = PI / 180; | |
const RAD_TO_DEG = 180 / PI; | |
const colors = [ | |
[ | |
'#df0049', | |
'#660671' | |
], | |
[ | |
'#00e857', | |
'#005291' | |
], | |
[ | |
'#2bebbc', | |
'#05798a' | |
], | |
[ | |
'#ffd200', | |
'#b06c00' | |
] | |
]; | |
var Vector2 = function(_x, _y) { | |
this.x = _x; | |
this.y = _y; | |
this.Length = function() { | |
return sqrt(this.SqrLength()); | |
}; | |
this.SqrLength = function() { | |
return (this.x * this.x) + (this.y * this.y); | |
}; | |
this.Add = function(_vec) { | |
this.x += _vec.x; | |
this.y += _vec.y; | |
}; | |
this.Sub = function(_vec) { | |
this.x -= _vec.x; | |
this.y -= _vec.y; | |
}; | |
this.Div = function(_f) { | |
this.x /= _f; | |
this.y /= _f; | |
}; | |
this.Mul = function(_f) { | |
this.x *= _f; | |
this.y *= _f; | |
}; | |
this.Normalize = function() { | |
const sqrLen = this.SqrLength(); | |
if (sqrLen !== 0) { | |
const factor = 1.0 / sqrt(sqrLen); | |
this.x *= factor; | |
this.y *= factor; | |
} | |
}; | |
this.Normalized = function() { | |
const sqrLen = this.SqrLength(); | |
if (sqrLen !== 0) { | |
const factor = 1.0 / sqrt(sqrLen); | |
return new Vector2(this.x * factor, this.y * factor); | |
} | |
return new Vector2(0, 0); | |
}; | |
}; | |
const EulerMass = function(_x, _y, _mass, _drag) { | |
this.position = new Vector2(_x, _y); | |
this.mass = _mass; | |
this.drag = _drag; | |
this.force = new Vector2(0, 0); | |
this.velocity = new Vector2(0, 0); | |
this.AddForce = function(_f) { | |
this.force.Add(_f); | |
}; | |
this.Integrate = function(_dt) { | |
const acc = this.CurrentForce(this.position); | |
acc.Div(this.mass); | |
const posDelta = new Vector2(this.velocity.x, this.velocity.y); | |
posDelta.Mul(_dt); | |
this.position.Add(posDelta); | |
acc.Mul(_dt); | |
this.velocity.Add(acc); | |
this.force = new Vector2(0, 0); | |
}; | |
this.CurrentForce = function(_pos, _vel) { | |
let speed; | |
const totalForce = new Vector2(this.force.x, this.force.y); | |
speed = this.velocity.Length(); | |
const dragVel = new Vector2(this.velocity.x, this.velocity.y); | |
dragVel.Mul(this.drag * this.mass * speed); | |
totalForce.Sub(dragVel); | |
return totalForce; | |
}; | |
}; | |
var ConfettiPaper = function(_x, _y) { | |
this.pos = new Vector2(_x, _y); | |
this.rotationSpeed = (random() * 600) + 800; | |
this.angle = DEG_TO_RAD * random() * 360; | |
this.rotation = DEG_TO_RAD * random() * 360; | |
this.cosA = 1.0; | |
this.size = 5.0; | |
this.oscillationSpeed = (random() * 1.5) + 0.5; | |
this.xSpeed = 40.0; | |
this.ySpeed = (random() * 60) + 50.0; | |
this.corners = new Array; | |
this.time = random(); | |
const ci = round(random() * (colors.length - 1)); | |
this.frontColor = colors[ci][0]; | |
this.backColor = colors[ci][1]; | |
let i = 0; | |
while (i < 4) { | |
const dx = cos(this.angle + (DEG_TO_RAD * ((i * 90) + 45))); | |
const dy = sin(this.angle + (DEG_TO_RAD * ((i * 90) + 45))); | |
this.corners[i] = new Vector2(dx, dy); | |
i++; | |
} | |
this.Update = function(_dt) { | |
this.time += _dt; | |
this.rotation += this.rotationSpeed * _dt; | |
this.cosA = cos(DEG_TO_RAD * this.rotation); | |
this.pos.x += cos(this.time * this.oscillationSpeed) * this.xSpeed * _dt; | |
this.pos.y += this.ySpeed * _dt; | |
if (this.pos.y > ConfettiPaper.bounds.y) { | |
this.pos.x = random() * ConfettiPaper.bounds.x; | |
this.pos.y = 0; | |
} | |
}; | |
this.Draw = function(_g) { | |
let i; | |
if (this.cosA > 0) { | |
_g.fillStyle = this.frontColor; | |
} else { | |
_g.fillStyle = this.backColor; | |
} | |
_g.beginPath(); | |
_g.moveTo((this.pos.x + (this.corners[0].x * this.size)), (this.pos.y + (this.corners[0].y * this.size * this.cosA))); | |
i = 1; | |
while (i < 4) { | |
_g.lineTo((this.pos.x + (this.corners[i].x * this.size)), (this.pos.y + (this.corners[i].y * this.size * this.cosA))); | |
i++; | |
} | |
_g.closePath(); | |
_g.fill(); | |
}; | |
}; | |
var ConfettiRibbon = function(_x, _y, _count, _dist, _thickness, _angle, _mass, _drag) { | |
this.particleDist = _dist; | |
this.particleCount = _count; | |
this.particleMass = _mass; | |
this.particleDrag = _drag; | |
this.particles = new Array; | |
const ci = round(random() * (colors.length - 1)); | |
this.frontColor = colors[ci][0]; | |
this.backColor = colors[ci][1]; | |
this.xOff = cos(DEG_TO_RAD * _angle) * _thickness; | |
this.yOff = sin(DEG_TO_RAD * _angle) * _thickness; | |
this.position = new Vector2(_x, _y); | |
this.prevPosition = new Vector2(_x, _y); | |
this.velocityInherit = (random() * 2) + 4; | |
this.time = random() * 100; | |
this.oscillationSpeed = (random() * 2) + 2; | |
this.oscillationDistance = (random() * 40) + 40; | |
this.ySpeed = (random() * 40) + 80; | |
let i = 0; | |
while (i < this.particleCount) { | |
this.particles[i] = new EulerMass(_x, _y - (i * this.particleDist), this.particleMass, this.particleDrag); | |
i++; | |
} | |
this.Update = function(_dt) { | |
let i; | |
i = 0; | |
this.time += _dt * this.oscillationSpeed; | |
this.position.y += this.ySpeed * _dt; | |
this.position.x += cos(this.time) * this.oscillationDistance * _dt; | |
this.particles[0].position = this.position; | |
const dX = this.prevPosition.x - (this.position.x); | |
const dY = this.prevPosition.y - (this.position.y); | |
const delta = sqrt((dX * dX) + (dY * dY)); | |
this.prevPosition = new Vector2(this.position.x, this.position.y); | |
i = 1; | |
while (i < this.particleCount) { | |
const dirP = Vector2.Sub(this.particles[i - 1].position, this.particles[i].position); | |
dirP.Normalize(); | |
dirP.Mul((delta / _dt) * this.velocityInherit); | |
this.particles[i].AddForce(dirP); | |
i++; | |
} | |
i = 1; | |
while (i < this.particleCount) { | |
this.particles[i].Integrate(_dt); | |
i++; | |
} | |
i = 1; | |
while (i < this.particleCount) { | |
const rp2 = new Vector2(this.particles[i].position.x, this.particles[i].position.y); | |
rp2.Sub(this.particles[i - 1].position); | |
rp2.Normalize(); | |
rp2.Mul(this.particleDist); | |
rp2.Add(this.particles[i - 1].position); | |
this.particles[i].position = rp2; | |
i++; | |
} | |
if (this.position.y > (ConfettiRibbon.bounds.y + (this.particleDist * this.particleCount))) { | |
this.Reset(); | |
} | |
}; | |
this.Reset = function() { | |
let ci; | |
let i; | |
this.position.y = -random() * ConfettiRibbon.bounds.y; | |
this.position.x = random() * ConfettiRibbon.bounds.x; | |
this.prevPosition = new Vector2(this.position.x, this.position.y); | |
this.velocityInherit = (random() * 2) + 4; | |
this.time = random() * 100; | |
this.oscillationSpeed = (random() * 2.0) + 1.5; | |
this.oscillationDistance = (random() * 40) + 40; | |
this.ySpeed = (random() * 40) + 80; | |
ci = round(random() * (colors.length - 1)); | |
this.frontColor = colors[ci][0]; | |
this.backColor = colors[ci][1]; | |
this.particles = new Array; | |
i = 0; | |
while (i < this.particleCount) { | |
this.particles[i] = new EulerMass(this.position.x, this.position.y - (i * this.particleDist), this.particleMass, this.particleDrag); | |
i++; | |
} | |
}; | |
this.Draw = function(_g) { | |
let i; | |
i = 0; | |
while (i < (this.particleCount - 1)) { | |
const p0 = new Vector2(this.particles[i].position.x + this.xOff, this.particles[i].position.y + this.yOff); | |
const p1 = new Vector2(this.particles[i + 1].position.x + this.xOff, this.particles[i + 1].position.y + this.yOff); | |
if (this.Side(this.particles[i].position.x, this.particles[i].position.y, this.particles[i + 1].position.x, this.particles[i + 1].position.y, p1.x, p1.y) < 0) { | |
_g.fillStyle = this.frontColor; | |
_g.strokeStyle = this.frontColor; | |
} else { | |
_g.fillStyle = this.backColor; | |
_g.strokeStyle = this.backColor; | |
} | |
if (i === 0) { | |
_g.beginPath(); | |
_g.moveTo(this.particles[i].position.x, this.particles[i].position.y); | |
_g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y); | |
_g.lineTo((this.particles[i + 1].position.x + p1.x) * 0.5, (this.particles[i + 1].position.y + p1.y) * 0.5); | |
_g.closePath(); | |
_g.stroke(); | |
_g.fill(); | |
_g.beginPath(); | |
_g.moveTo(p1.x, p1.y); | |
_g.lineTo(p0.x, p0.y); | |
_g.lineTo((this.particles[i + 1].position.x + p1.x) * 0.5, (this.particles[i + 1].position.y + p1.y) * 0.5); | |
_g.closePath(); | |
_g.stroke(); | |
_g.fill(); | |
} else if (i === (this.particleCount - 2)) { | |
_g.beginPath(); | |
_g.moveTo(this.particles[i].position.x, this.particles[i].position.y); | |
_g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y); | |
_g.lineTo((this.particles[i].position.x + p0.x) * 0.5, (this.particles[i].position.y + p0.y) * 0.5); | |
_g.closePath(); | |
_g.stroke(); | |
_g.fill(); | |
_g.beginPath(); | |
_g.moveTo(p1.x, p1.y); | |
_g.lineTo(p0.x, p0.y); | |
_g.lineTo((this.particles[i].position.x + p0.x) * 0.5, (this.particles[i].position.y + p0.y) * 0.5); | |
_g.closePath(); | |
_g.stroke(); | |
_g.fill(); | |
} else { | |
_g.beginPath(); | |
_g.moveTo(this.particles[i].position.x, this.particles[i].position.y); | |
_g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y); | |
_g.lineTo(p1.x, p1.y); | |
_g.lineTo(p0.x, p0.y); | |
_g.closePath(); | |
_g.stroke(); | |
_g.fill(); | |
} | |
i++; | |
} | |
}; | |
this.Side = (x1, y1, x2, y2, x3, y3) => ((x1 - x2) * (y3 - y2)) - ((y1 - y2) * (x3 - x2)); | |
}; | |
Vector2.Lerp = (_vec0, _vec1, _t) => new Vector2(((_vec1.x - (_vec0.x)) * _t) + _vec0.x, ((_vec1.y - (_vec0.y)) * _t) + _vec0.y); | |
Vector2.Distance = (_vec0, _vec1) => sqrt(Vector2.SqrDistance(_vec0, _vec1)); | |
Vector2.SqrDistance = function(_vec0, _vec1) { | |
const x = _vec0.x - (_vec1.x); | |
const y = _vec0.y - (_vec1.y); | |
return (x * x) + (y * y) + (z * z); | |
}; | |
Vector2.Scale = (_vec0, _vec1) => new Vector2(_vec0.x * _vec1.x, _vec0.y * _vec1.y); | |
Vector2.Min = (_vec0, _vec1) => new Vector2(Math.min(_vec0.x, _vec1.x), Math.min(_vec0.y, _vec1.y)); | |
Vector2.Max = (_vec0, _vec1) => new Vector2(Math.max(_vec0.x, _vec1.x), Math.max(_vec0.y, _vec1.y)); | |
Vector2.ClampMagnitude = function(_vec0, _len) { | |
const vecNorm = _vec0.Normalized; | |
return new Vector2(vecNorm.x * _len, vecNorm.y * _len); | |
}; | |
Vector2.Sub = (_vec0, _vec1) => new Vector2(_vec0.x - (_vec1.x), _vec0.y - (_vec1.y), _vec0.z - (_vec1.z)); | |
ConfettiPaper.bounds = new Vector2(0, 0); | |
ConfettiRibbon.bounds = new Vector2(0, 0); | |
let confetti = {}; | |
confetti.Context = function(canvas) { | |
let i = 0; | |
const canvasParent = window; | |
let canvasWidth = canvasParent.innerWidth; | |
let canvasHeight = canvasParent.innerHeight; | |
canvas.width = canvasWidth; | |
canvas.height = canvasHeight; | |
const context = canvas.getContext('2d'); | |
const interval = null; | |
const confettiRibbons = new Array; | |
ConfettiRibbon.bounds = new Vector2(canvasWidth, canvasHeight); | |
i = 0; | |
while (i < confettiRibbonCount) { | |
confettiRibbons[i] = new ConfettiRibbon(random() * canvasWidth, -random() * canvasHeight * 2, ribbonPaperCount, ribbonPaperDist, ribbonPaperThick, 45, 1, 0.05); | |
i++; | |
} | |
const confettiPapers = new Array; | |
ConfettiPaper.bounds = new Vector2(canvasWidth, canvasHeight); | |
i = 0; | |
while (i < confettiPaperCount) { | |
confettiPapers[i] = new ConfettiPaper(random() * canvasWidth, random() * canvasHeight); | |
i++; | |
} | |
this.resize = function() { | |
canvasWidth = canvasParent.innerWidth; | |
canvasHeight = canvasParent.innerHeight; | |
canvas.width = canvasWidth; | |
canvas.height = canvasHeight; | |
ConfettiPaper.bounds = new Vector2(canvasWidth, canvasHeight); | |
ConfettiRibbon.bounds = new Vector2(canvasWidth, canvasHeight); | |
}; | |
this.start = function() { | |
let context; | |
this.stop(); | |
context = this; | |
this.update(); | |
}; | |
this.stop = function() { | |
cAF(this.interval); | |
}; | |
this.update = function() { | |
let i; | |
i = 0; | |
context.clearRect(0, 0, canvas.width, canvas.height); | |
i = 0; | |
while (i < confettiPaperCount) { | |
confettiPapers[i].Update(duration); | |
confettiPapers[i].Draw(context); | |
i++; | |
} | |
i = 0; | |
while (i < confettiRibbonCount) { | |
confettiRibbons[i].Update(duration); | |
confettiRibbons[i].Draw(context); | |
i++; | |
} | |
this.interval = rAF(function() { | |
confetti.update(); | |
}); | |
}; | |
}; | |
confetti = new (confetti.Context)(canvas); | |
confetti.start(); | |
window.addEventListener('resize', function(event) { | |
confetti.resize(); | |
}); | |
return confetti; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment