I have a function here, as soon as the highscore is cracked, a fireworks display is played. Now I want the fireworks to stop as soon as the Start button is clicked again. Do I need an IF condition associated with the Start button, or what would that look like in the code?
I don't know the command, I tried firework.end, but it didn't work.
fireworks.start(); //Start the fireworks.
As I said, I would like the fireworks to stop as soon as a new game is started (so click the Start button).
_addExplosioncalls itself recursively, so by adding another property called _running, we can flip this in a function called stop:
stop: function() {
this._running = false;
window.clearTimeout();
for (var i = 0; i < this._particles.length; i++) {
this._particles[i].parentNode.removeChild(this._particles[i]);
}
},
Inside _addExplosion we can inspect this to stop the "loop":
if (this._running) {
window.setTimeout(function () { return fireworks._addExplosion.apply(fireworks); },
this._random(this._interval[1] - this._interval[0]) + this._interval[0]);
}
You can then declare a function to be executed on click:
function stopFireworks() {
fireworks.stop();
}
And in your HTML:
<button onclick="stopFireworks()">Stop</button>
Full example:
var fireworks = {
///////////////////////////// configuration ////////////////////////////
// random colors
_color: ['#D0D0D0', '#FF0000', '#FFFF00', '#22FF00', '#2040FF', '#00CCFF', '#FF00FF', '#A319D6'],
// gravity factor
_gravity: 0.07,
// air resistance factor
_resistance: 0.975,
// zIndex of particles
_zIndex: 20000,
// maximal age of particles (in msec)
_maxAge: 2000,
// interval of appearing explosions (in msec)
_interval: [500, 2500],
// amount of particles per explosion
_particlesPerExplosion: 40,
// maximal speed of particle at moment of explosion
_speed: 5,
// minimal/maximal size of particle
_minSize: 8,
_maxSize: 12,
_running: true,
///////////////////////////// private vars /////////////////////////////
_particles: [],
_bodyWidth: 0,
_bodyHeight: 0,
_count: 0,
_lastInterval: 0,
////////////////////////////// functions ///////////////////////////////
// init fireworks
init: function () {
this._addEventListener(window, 'resize', function () { return fireworks.resize.apply(fireworks); });
this._addEventListener(window, 'load', function () { return fireworks.start.apply(fireworks); });
},
// add an event listener
_addEventListener: function (el, name, handler) {
if (el.addEventListener)
el.addEventListener(name, handler, false);
else if (el.attachEvent)
el.attachEvent('on' + name, handler);
},
// start fireworks
start: function () {
// init window size
this.resize();
// start to move particles
this._animFn = function () { fireworks._move(); };
this._lastInterval = this._time();
requestAnimFrame(this._animFn);
this._addExplosion();
},
// get current time
_time: function () {
return +new Date();
},
// return a random integer
_random: function (value) {
return Math.random() * value;
},
// return a random array element
_randomArray: function (arr) {
return arr[
Math.floor(
Math.random() * (arr.length)
)
];
},
// add a new explosion
_addExplosion: function () {
var x = Math.floor(this._random(this._bodyWidth)),
y = Math.floor((this._random(.5) + .1) * this._bodyHeight),
dx = this._random(10) - 5,
dy = this._random(-2) - 1,
c1 = this._randomArray(this._color),
c2 = this._randomArray(this._color);
for (var i = 0; i < this._particlesPerExplosion; i++) {
if (this._running) {
this._createParticle(
x,
y,
dx,
dy,
i / (this._particlesPerExplosion - 1) * 180 * Math.PI,
this._random(this._speed),
this._random(1) > .5 ? c1 : c2
);
}
}
if (this._running) {
window.setTimeout(
function () {
fireworks._addExplosion.apply(fireworks);
},
this._random(this._interval[1] - this._interval[0]) + this._interval[0]
);
}
},
stop: function() {
this._running = false;
window.clearTimeout();
for (var i = 0; i < this._particles.length; i++) {
this._particles[i].parentNode.removeChild(this._particles[i]);
}
},
// creates a new particle
_createParticle: function (x, y, dx, dy, rot, speed, color) {
var el = null,
foundEl = false,
p = this._particles;
// look for old particle
for (var i = 0, l = p.length; i < l; i++)
if (p[i].data.age > 1) {
el = p[i];
foundEl = true;
break;
}
// create span child for particles
if (!foundEl) {
el = document.createElement('div');
el.className = 'particle';
el.style.position = 'absolute';
el.style.fontSize = this._maxSize + 'px';
el.style.zIndex = this._zIndex;
el.style.width = this._maxSize + 'px';
el.style.textAlign = 'center';
el.style.overflow = 'hidden';
el.innerHTML = '●';
}
el.style.left = x + 'px';
el.style.top = y + 'px';
el.style.color = color;
el.data = {
x: x,
y: y,
dx: Math.cos(rot) * speed + dx,
dy: Math.sin(rot) * speed + dy,
color: color,
age: Math.random() * .25
};
if (!foundEl) {
document.getElementsByTagName('body')[0].appendChild(el);
this._particles.push(el);
}
},
// move existing particles
_move: function () {
requestAnimFrame(this._animFn);
// calculate movement factor
var dif = this._time() - this._lastInterval;
this._lastInterval = this._time();
var delta = dif / 20,
el,
d,
p = this._particles,
r = Math.pow(this._resistance, delta),
g = this._gravity * delta,
a = dif / this._maxAge;
for (var i = 0, l = p.length; i < l; i++) {
el = p[i];
d = el.data;
if (d.age > 1)
continue;
d.age += a;
d.dy += g;
d.dx *= r;
d.dy *= r;
d.x += d.dx * delta;
d.y += d.dy * delta;
if (d.x < 0) {
d.dx *= -1;
d.x = 0;
}
else if (d.x > this._bodyWidth) {
d.dx *= -1;
d.x = this._bodyWidth;
}
if (d.y < 0) {
d.dy *= -1;
d.y = 0;
}
else if (d.y > this._bodyHeight) {
d.dy *= -1;
d.y = this._bodyHeight;
}
if (d.age > 1)
d.x = d.y = 0;
el.style.left = d.x + 'px';
el.style.top = d.y + 'px';
el.style.color = (Math.random() * .5 + d.age >= 1) ? 'transparent' : d.color;
el.style.fontSize = Math.max(this._minSize, (1 - d.age) * this._maxSize) + 'px';
}
},
// calculate new positions for all particles
resize: function () {
// get new width and height
this._bodyWidth = this._getWindowWidth() - this._maxSize;
this._bodyHeight = this._getWindowHeight() - this._maxSize - 10;
},
// get window width
_getWindowWidth: function () {
return document.getElementsByTagName('body')[0].offsetWidth;
},
// get window height
_getWindowHeight: function () {
var h = Math.max(self.innerHeight || 0, window.innerHeight || 0);
if (document.documentElement)
h = Math.max(h, document.documentElement.clientHeight || 0);
if (document.body) {
h = Math.max(h, document.body.clientHeight || 0);
h = Math.max(h, document.body.scrollHeight || 0);
h = Math.max(h, document.body.offsetHeight || 0);
}
return h;
}
};
// shim layer with setTimeout fallback
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (cb) {
window.setTimeout(cb, 1000 / 60);
};
})();
function stopFireworks() {
fireworks.stop();
}
fireworks.start();
<html>
<head></head>
<body>
<button onclick="stopFireworks()">Stop</button>
</body>
</html>
Related
I'm trying to refactor a website inside a Vue 3 single page app.
Everything is working but I cannot understand which is the best way to insert and execute some javascript functions...
In my homepage, that now is a component, I use this function to create a parallax star + mountain landscape
document.addEventListener('DOMContentLoaded', () => {
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
// Terrain stuff.
var background = document.getElementById("bg-canvas")
var backgroundHome = document.getElementById("bg-home")
var bgCtx = background.getContext("2d"),
width = window.innerWidth,
height = window.innerHeight;
(height < 400) ? height = 400: height;
background.width = width;
background.height = height;
function Terrain(options) {
options = options || {};
this.terrain = document.createElement("canvas");
this.terCtx = this.terrain.getContext("2d");
this.scrollDelay = options.scrollDelay || 90;
this.lastScroll = new Date().getTime();
this.terrain.width = width;
this.terrain.height = height;
this.fillStyle = options.fillStyle || "#494776";
this.mHeight = options.mHeight || height;
// generate
this.points = [];
var displacement = options.displacement || 140,
power = Math.pow(2, Math.ceil(Math.log(width) / (Math.log(2))));
// set the start height and end height for the terrain
this.points[0] = this.mHeight; //(this.mHeight - (Math.random() * this.mHeight / 2)) - displacement;
this.points[power] = this.points[0];
// create the rest of the points
for (var i = 1; i < power; i *= 2) {
for (var j = (power / i) / 2; j < power; j += power / i) {
this.points[j] = ((this.points[j - (power / i) / 2] + this.points[j + (power / i) / 2]) / 2) + Math.floor(Math.random() * -displacement + displacement);
}
displacement *= 0.6;
}
background.after(this.terrain);
}
Terrain.prototype.update = function() {
// draw the terrain
this.terCtx.clearRect(0, 0, width, height);
this.terCtx.fillStyle = this.fillStyle;
if (new Date().getTime() > this.lastScroll + this.scrollDelay) {
this.lastScroll = new Date().getTime();
this.points.push(this.points.shift());
}
this.terCtx.beginPath();
for (var i = 0; i <= width; i++) {
if (i === 0) {
this.terCtx.moveTo(0, this.points[0]);
} else if (this.points[i] !== undefined) {
this.terCtx.lineTo(i, this.points[i]);
}
}
this.terCtx.lineTo(width, this.terrain.height);
this.terCtx.lineTo(0, this.terrain.height);
this.terCtx.lineTo(0, this.points[0]);
this.terCtx.fill();
}
// Second canvas used for the stars
bgCtx.fillStyle = '#05004c';
bgCtx.fillRect(0, 0, width, height);
// stars
function Star(options) {
this.size = Math.random() * 2;
this.speed = Math.random() * .05;
this.x = options.x;
this.y = options.y;
}
Star.prototype.reset = function() {
this.size = Math.random() * 2;
this.speed = Math.random() * .05;
this.x = width;
this.y = Math.random() * height;
}
Star.prototype.update = function() {
this.x -= this.speed;
if (this.x < 0) {
this.reset();
} else {
bgCtx.fillRect(this.x, this.y, this.size, this.size);
}
}
function ShootingStar() {
this.reset();
}
ShootingStar.prototype.reset = function() {
this.x = Math.random() * width;
this.y = 0;
this.len = (Math.random() * 80) + 10;
this.speed = (Math.random() * 10) + 6;
this.size = (Math.random() * 1) + 0.1;
// this is used so the shooting stars arent constant
this.waitTime = new Date().getTime() + (Math.random() * 3000) + 500;
this.active = false;
}
ShootingStar.prototype.update = function() {
if (this.active) {
this.x -= this.speed;
this.y += this.speed;
if (this.x < 0 || this.y >= height) {
this.reset();
} else {
bgCtx.lineWidth = this.size;
bgCtx.beginPath();
bgCtx.moveTo(this.x, this.y);
bgCtx.lineTo(this.x + this.len, this.y - this.len);
bgCtx.stroke();
}
} else {
if (this.waitTime < new Date().getTime()) {
this.active = true;
}
}
}
var entities = [];
// init the stars
for (var i = 0; i < height; i++) {
entities.push(new Star({
x: Math.random() * width,
y: Math.random() * height
}));
}
// Add 2 shooting stars that just cycle.
entities.push(new ShootingStar());
entities.push(new ShootingStar());
entities.push(new Terrain({
displacement: 150,
scrollDelay: 20,
fillStyle: "#221445",
mHeight: height / 2
}));
entities.push(new Terrain({
displacement: 120,
scrollDelay: 50,
fillStyle: "#2e1f56",
mHeight: (height / 2) - 30
}));
entities.push(new Terrain({
mHeight: (height / 2) - 60
}));
//animate background
function animate() {
bgCtx.fillStyle = '#055e8f';
bgCtx.fillRect(0, 0, width, height);
bgCtx.fillStyle = '#ffffff';
bgCtx.strokeStyle = '#ffffff';
var entLen = entities.length;
while (entLen--) {
entities[entLen].update();
}
requestAnimationFrame(animate);
}
animate();
});
Which is the most efficient way to execute this when my homepage component is mounted?
I'm trying to update an existing particle animation. In this demo, the particles are just lines with different lineWidths with random sizes and rotation as they fall down.
My goal is to replace the lines with a different shape, which looks like the image below keeping everything else as is.
I've already changed the shape, but I'm having a couple issues:
It doesn't rotate anymore like in the original demo link posted above.
Since, I replaced the lines with an image of the shape, I'm also facing performance issues if I increase the particles.
If I randomize the size, it keeps updating the size of the shape constantly without keeping the first random size.
context.drawImage(svg, x, y, 20, 40)
|
v
context.drawImage(svg, x, y, Math.random() * 20, Math.random() * 40)
Could anybody point me in the right direction on I should go about fixing the above. Appreciate any help!
var confetti = {
maxCount: 150, //set max confetti count
speed: 1, //set the particle animation speed
frameInterval: 30, //the confetti animation frame interval in milliseconds
alpha: 1.0, //the alpha opacity of the confetti (between 0 and 1, where 1 is opaque and 0 is invisible)
gradient: false, //whether to use gradients for the confetti particles
start: null, //call to start confetti animation (with optional timeout in milliseconds, and optional min and max random confetti count)
stop: null, //call to stop adding confetti
toggle: null, //call to start or stop the confetti animation depending on whether it's already running
pause: null, //call to freeze confetti animation
resume: null, //call to unfreeze confetti animation
togglePause: null, //call to toggle whether the confetti animation is paused
remove: null, //call to stop the confetti animation and remove all confetti immediately
isPaused: null, //call and returns true or false depending on whether the confetti animation is paused
isRunning: null //call and returns true or false depending on whether the animation is running
};
(function() {
confetti.start = startConfetti;
confetti.stop = stopConfetti;
confetti.toggle = toggleConfetti;
confetti.pause = pauseConfetti;
confetti.resume = resumeConfetti;
confetti.togglePause = toggleConfettiPause;
confetti.isPaused = isConfettiPaused;
confetti.remove = removeConfetti;
confetti.isRunning = isConfettiRunning;
var supportsAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame;
var colors = ["rgba(30,144,255,", "rgba(107,142,35,", "rgba(255,215,0,", "rgba(255,192,203,", "rgba(106,90,205,", "rgba(173,216,230,", "rgba(238,130,238,", "rgba(152,251,152,", "rgba(70,130,180,", "rgba(244,164,96,", "rgba(210,105,30,", "rgba(220,20,60,"];
var streamingConfetti = false;
var animationTimer = null;
var pause = false;
var lastFrameTime = Date.now();
var particles = [];
var waveAngle = 0;
var context = null;
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function resetParticle(particle, width, height) {
particle.color = colors[(Math.random() * colors.length) | 0] + (confetti.alpha + ")");
particle.color2 = colors[(Math.random() * colors.length) | 0] + (confetti.alpha + ")");
particle.x = getRandomInt(0, width);
particle.y = getRandomInt(-height / 2, 0);
particle.diameter = Math.random() * 10 + 5;
particle.tilt = Math.random() * 10 - 10;
particle.tiltAngleIncrement = Math.random() * 0.07 + 0.05;
particle.tiltAngle = Math.random() * Math.PI;
return particle;
}
function toggleConfettiPause() {
if (pause)
resumeConfetti();
else
pauseConfetti();
}
function isConfettiPaused() {
return pause;
}
function pauseConfetti() {
pause = true;
}
function resumeConfetti() {
pause = false;
runAnimation();
}
function runAnimation() {
if (pause)
return;
else if (particles.length === 0) {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
animationTimer = null;
} else {
var now = Date.now();
var delta = now - lastFrameTime;
if (!supportsAnimationFrame || delta > confetti.frameInterval) {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
updateParticles();
drawParticles(context);
lastFrameTime = now - (delta % confetti.frameInterval);
}
animationTimer = requestAnimationFrame(runAnimation);
}
}
function startConfetti(timeout, min, max) {
var width = window.innerWidth;
var height = window.innerHeight;
window.requestAnimationFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, confetti.frameInterval);
};
})();
var canvas = document.getElementById("confetti-canvas");
if (canvas === null) {
canvas = document.createElement("canvas");
canvas.setAttribute("id", "confetti-canvas");
canvas.setAttribute("style", "display:block;z-index:999999;pointer-events:none;position:fixed;top:0");
document.body.prepend(canvas);
canvas.width = width;
canvas.height = height;
window.addEventListener("resize", function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}, true);
context = canvas.getContext("2d");
} else if (context === null)
context = canvas.getContext("2d");
var count = confetti.maxCount;
if (min) {
if (max) {
if (min == max)
count = particles.length + max;
else {
if (min > max) {
var temp = min;
min = max;
max = temp;
}
count = particles.length + ((Math.random() * (max - min) + min) | 0);
}
} else
count = particles.length + min;
} else if (max)
count = particles.length + max;
while (particles.length < count)
particles.push(resetParticle({}, width, height));
streamingConfetti = true;
pause = false;
runAnimation();
if (timeout) {
window.setTimeout(stopConfetti, timeout);
}
}
function stopConfetti() {
streamingConfetti = false;
}
function removeConfetti() {
stop();
pause = false;
particles = [];
}
function toggleConfetti() {
if (streamingConfetti)
stopConfetti();
else
startConfetti();
}
function isConfettiRunning() {
return streamingConfetti;
}
function drawParticles(context) {
var particle;
var x, y, x2, y2;
for (var i = 0; i < particles.length; i++) {
particle = particles[i];
particleWidth = particle.diameter;
x2 = particle.x + particle.tilt;
x = x2 + particle.diameter / 2;
y = particle.y;
var svg = new Image();
svg.src = 'https://i.postimg.cc/TPBmVXH1/confetti.png';
context.drawImage(svg, x, y, 20, 40)
/*context.beginPath();
context.lineWidth = particle.diameter;
x2 = particle.x + particle.tilt;
x = x2 + particle.diameter / 2;
y2 = particle.y + particle.tilt + particle.diameter / 2;
if (confetti.gradient) {
var gradient = context.createLinearGradient(x, particle.y, x2, y2);
gradient.addColorStop("0", particle.color);
gradient.addColorStop("1.0", particle.color2);
context.strokeStyle = gradient;
} else
context.strokeStyle = particle.color;
context.moveTo(x, particle.y);
context.lineTo(x2, y2);
context.stroke();*/
}
}
function updateParticles() {
var width = window.innerWidth;
var height = window.innerHeight;
var particle;
waveAngle += 0.01;
for (var i = 0; i < particles.length; i++) {
particle = particles[i];
if (!streamingConfetti && particle.y < -15)
particle.y = height + 100;
else {
particle.tiltAngle += particle.tiltAngleIncrement;
particle.x += Math.sin(waveAngle) - 0.5;
particle.y += (Math.cos(waveAngle) + particle.diameter + confetti.speed) * 0.5;
particle.tilt = Math.sin(particle.tiltAngle) * 15;
}
if (particle.x > width + 20 || particle.x < -20 || particle.y > height) {
if (streamingConfetti && particles.length <= confetti.maxCount)
resetParticle(particle, width, height);
else {
particles.splice(i, 1);
i--;
}
}
}
}
startConfetti(5000, 20, 25)
})();
html {
height: 100%;
}
body,
html {
margin: 0;
}
body {
background: black;
}
Ok so here is what I did:
I changed drawParticles to apply the particle.tilt.
I moved the svg variable to the top so it is reused and not loaded multiple times.
I did set the random size in resetParticle so it does not change afterwards.
var confetti = {
maxCount: 150, //set max confetti count
speed: 1, //set the particle animation speed
frameInterval: 30, //the confetti animation frame interval in milliseconds
alpha: 1.0, //the alpha opacity of the confetti (between 0 and 1, where 1 is opaque and 0 is invisible)
gradient: false, //whether to use gradients for the confetti particles
start: null, //call to start confetti animation (with optional timeout in milliseconds, and optional min and max random confetti count)
stop: null, //call to stop adding confetti
toggle: null, //call to start or stop the confetti animation depending on whether it's already running
pause: null, //call to freeze confetti animation
resume: null, //call to unfreeze confetti animation
togglePause: null, //call to toggle whether the confetti animation is paused
remove: null, //call to stop the confetti animation and remove all confetti immediately
isPaused: null, //call and returns true or false depending on whether the confetti animation is paused
isRunning: null //call and returns true or false depending on whether the animation is running
};
(function () {
confetti.start = startConfetti;
confetti.stop = stopConfetti;
confetti.toggle = toggleConfetti;
confetti.pause = pauseConfetti;
confetti.resume = resumeConfetti;
confetti.togglePause = toggleConfettiPause;
confetti.isPaused = isConfettiPaused;
confetti.remove = removeConfetti;
confetti.isRunning = isConfettiRunning;
var supportsAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame;
var colors = ["rgba(30,144,255,", "rgba(107,142,35,", "rgba(255,215,0,", "rgba(255,192,203,", "rgba(106,90,205,", "rgba(173,216,230,", "rgba(238,130,238,", "rgba(152,251,152,", "rgba(70,130,180,", "rgba(244,164,96,", "rgba(210,105,30,", "rgba(220,20,60,"];
var streamingConfetti = false;
var animationTimer = null;
var pause = false;
var lastFrameTime = Date.now();
var particles = [];
var waveAngle = 0;
var context = null;
var sizes = [];
var svg = new Image();
svg.src = 'https://i.postimg.cc/TPBmVXH1/confetti.png';
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function resetParticle(particle, width, height) {
particle.color = colors[(Math.random() * colors.length) | 0] + (confetti.alpha + ")");
particle.color2 = colors[(Math.random() * colors.length) | 0] + (confetti.alpha + ")");
particle.x = getRandomInt(0, width);
particle.y = getRandomInt(-height / 2, 0);
particle.diameter = Math.random() * 10 + 5;
particle.tilt = Math.random() * 10 - 10;
particle.tiltAngleIncrement = Math.random() * 0.07 + 0.05;
particle.tiltAngle = Math.random() * Math.PI;
particle.width = Math.random() * 20
particle.height = Math.random() * 40
return particle;
}
function toggleConfettiPause() {
if (pause)
resumeConfetti();
else
pauseConfetti();
}
function isConfettiPaused() {
return pause;
}
function pauseConfetti() {
pause = true;
}
function resumeConfetti() {
pause = false;
runAnimation();
}
function runAnimation() {
if (pause)
return;
else if (particles.length === 0) {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
animationTimer = null;
} else {
var now = Date.now();
var delta = now - lastFrameTime;
if (!supportsAnimationFrame || delta > confetti.frameInterval) {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
updateParticles();
drawParticles(context);
lastFrameTime = now - (delta % confetti.frameInterval);
}
animationTimer = requestAnimationFrame(runAnimation);
}
}
function startConfetti(timeout, min, max) {
var width = window.innerWidth;
var height = window.innerHeight;
window.requestAnimationFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
return window.setTimeout(callback, confetti.frameInterval);
};
})();
var canvas = document.getElementById("confetti-canvas");
if (canvas === null) {
canvas = document.createElement("canvas");
canvas.setAttribute("id", "confetti-canvas");
canvas.setAttribute("style", "display:block;z-index:999999;pointer-events:none;position:fixed;top:0");
document.body.prepend(canvas);
canvas.width = width;
canvas.height = height;
window.addEventListener("resize", function () {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}, true);
context = canvas.getContext("2d");
} else if (context === null)
context = canvas.getContext("2d");
var count = confetti.maxCount;
if (min) {
if (max) {
if (min == max)
count = particles.length + max;
else {
if (min > max) {
var temp = min;
min = max;
max = temp;
}
count = particles.length + ((Math.random() * (max - min) + min) | 0);
}
} else
count = particles.length + min;
} else if (max)
count = particles.length + max;
while (particles.length < count)
particles.push(resetParticle({}, width, height));
streamingConfetti = true;
pause = false;
runAnimation();
if (timeout) {
window.setTimeout(stopConfetti, timeout);
}
}
function stopConfetti() {
streamingConfetti = false;
}
function removeConfetti() {
stop();
pause = false;
particles = [];
}
function toggleConfetti() {
if (streamingConfetti)
stopConfetti();
else
startConfetti();
}
function isConfettiRunning() {
return streamingConfetti;
}
function drawParticles(context) {
var particle;
var x, y, x2, y2;
for (var i = 0; i < particles.length; i++) {
particle = particles[i];
particleWidth = particle.diameter;
x2 = particle.x + particle.tilt;
x = x2 + particle.diameter / 2;
y = particle.y;
context.save();
context.translate(x, y);
context.rotate(particle.tilt / 180 * Math.PI);
context.translate(-x, -y);
context.drawImage(svg, x, y, particle.width, particle.height);
context.restore();
/*context.beginPath();
context.lineWidth = particle.diameter;
x2 = particle.x + particle.tilt;
x = x2 + particle.diameter / 2;
y2 = particle.y + particle.tilt + particle.diameter / 2;
if (confetti.gradient) {
var gradient = context.createLinearGradient(x, particle.y, x2, y2);
gradient.addColorStop("0", particle.color);
gradient.addColorStop("1.0", particle.color2);
context.strokeStyle = gradient;
} else
context.strokeStyle = particle.color;
context.moveTo(x, particle.y);
context.lineTo(x2, y2);
context.stroke();*/
}
}
function updateParticles() {
var width = window.innerWidth;
var height = window.innerHeight;
var particle;
waveAngle += 0.01;
for (var i = 0; i < particles.length; i++) {
particle = particles[i];
if (!streamingConfetti && particle.y < -15)
particle.y = height + 100;
else {
particle.tiltAngle += particle.tiltAngleIncrement;
particle.x += Math.sin(waveAngle) - 0.5;
particle.y += (Math.cos(waveAngle) + particle.diameter + confetti.speed) * 0.5;
particle.tilt = Math.sin(particle.tiltAngle) * 15;
}
if (particle.x > width + 20 || particle.x < -20 || particle.y > height) {
if (streamingConfetti && particles.length <= confetti.maxCount)
resetParticle(particle, width, height);
else {
particles.splice(i, 1);
i--;
}
}
}
}
startConfetti(5000, 20, 25)
})();
html {
height: 100%;
}
body, html {
margin: 0;
}
body {
background: black;
}
I've found this codepen that I'm integrating on a small website I have for a project. I don't want to put too much time into it, so I'll just be using a codepen I found. I'll do some adjustments to it, like the shape.
I managed to implement it, but now I'm having trouble to change the colors and the shape of the confetti.
The colors are completely random and I'd love for this to just be simple.
Also, I can't seem to be able to change the shape. I can only adjust the size.
If anyone here feels like giving me a nudge in the right direction, that'd be great!
'use strict';
// If set to true, the user must press
// UP UP DOWN ODWN LEFT RIGHT LEFT RIGHT A B
// to trigger the confetti with a random color theme.
// Otherwise the confetti constantly falls.
var onlyOnKonami = false;
$(function() {
// Globals
var $window = $(window)
, random = Math.random
, cos = Math.cos
, sin = Math.sin
, PI = Math.PI
, PI2 = PI * 2
, timer = undefined
, frame = undefined
, confetti = [];
// Settings
var konami = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]
, pointer = 0;
var particles = 150
, spread = 40
, sizeMin = 3
, sizeMax = 12 - sizeMin
, eccentricity = 10
, deviation = 100
, dxThetaMin = -.1
, dxThetaMax = -dxThetaMin - dxThetaMin
, dyMin = .13
, dyMax = .18
, dThetaMin = .4
, dThetaMax = .7 - dThetaMin;
var colorThemes = [
function() {
return color(200 * random()|0, 200 * random()|0, 200 * random()|0);
}, function() {
var black = 200 * random()|0; return color(200, black, black);
}, function() {
var black = 200 * random()|0; return color(black, 200, black);
}, function() {
var black = 200 * random()|0; return color(black, black, 200);
}, function() {
return color(200, 100, 200 * random()|0);
}, function() {
return color(200 * random()|0, 200, 200);
}, function() {
var black = 256 * random()|0; return color(black, black, black);
}, function() {
return colorThemes[random() < .5 ? 1 : 2]();
}, function() {
return colorThemes[random() < .5 ? 3 : 5]();
}, function() {
return colorThemes[random() < .5 ? 2 : 4]();
}
];
function color(r, g, b) {
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
// Cosine interpolation
function interpolation(a, b, t) {
return (1-cos(PI*t))/2 * (b-a) + a;
}
// Create a 1D Maximal Poisson Disc over [0, 1]
var radius = 1/eccentricity, radius2 = radius+radius;
function createPoisson() {
// domain is the set of points which are still available to pick from
// D = union{ [d_i, d_i+1] | i is even }
var domain = [radius, 1-radius], measure = 1-radius2, spline = [0, 1];
while (measure) {
var dart = measure * random(), i, l, interval, a, b, c, d;
// Find where dart lies
for (i = 0, l = domain.length, measure = 0; i < l; i += 2) {
a = domain[i], b = domain[i+1], interval = b-a;
if (dart < measure+interval) {
spline.push(dart += a-measure);
break;
}
measure += interval;
}
c = dart-radius, d = dart+radius;
// Update the domain
for (i = domain.length-1; i > 0; i -= 2) {
l = i-1, a = domain[l], b = domain[i];
// c---d c---d Do nothing
// c-----d c-----d Move interior
// c--------------d Delete interval
// c--d Split interval
// a------b
if (a >= c && a < d)
if (b > d) domain[l] = d; // Move interior (Left case)
else domain.splice(l, 2); // Delete interval
else if (a < c && b > c)
if (b <= d) domain[i] = c; // Move interior (Right case)
else domain.splice(i, 0, c, d); // Split interval
}
// Re-measure the domain
for (i = 0, l = domain.length, measure = 0; i < l; i += 2)
measure += domain[i+1]-domain[i];
}
return spline.sort();
}
// Create the overarching container
var container = document.createElement('div');
container.style.position = 'fixed';
container.style.top = '0';
container.style.left = '0';
container.style.width = '100%';
container.style.height = '0';
container.style.overflow = 'visible';
container.style.zIndex = '9999';
// Confetto constructor
function Confetto(theme) {
this.frame = 0;
this.outer = document.createElement('div');
this.inner = document.createElement('div');
this.outer.appendChild(this.inner);
var outerStyle = this.outer.style, innerStyle = this.inner.style;
outerStyle.position = 'absolute';
outerStyle.width = (sizeMin + sizeMax * random()) + 'px';
outerStyle.height = (sizeMin + sizeMax * random()) + 'px';
innerStyle.width = '100%';
innerStyle.height = '100%';
innerStyle.backgroundColor = theme();
outerStyle.perspective = '50px';
outerStyle.transform = 'rotate(' + (360 * random()) + 'deg)';
this.axis = 'rotate3D(' +
cos(360 * random()) + ',' +
cos(360 * random()) + ',0,';
this.theta = 360 * random();
this.dTheta = dThetaMin + dThetaMax * random();
innerStyle.transform = this.axis + this.theta + 'deg)';
this.x = $window.width() * random();
this.y = -deviation;
this.dx = sin(dxThetaMin + dxThetaMax * random());
this.dy = dyMin + dyMax * random();
outerStyle.left = this.x + 'px';
outerStyle.top = this.y + 'px';
// Create the periodic spline
this.splineX = createPoisson();
this.splineY = [];
for (var i = 1, l = this.splineX.length-1; i < l; ++i)
this.splineY[i] = deviation * random();
this.splineY[0] = this.splineY[l] = deviation * random();
this.update = function(height, delta) {
this.frame += delta;
this.x += this.dx * delta;
this.y += this.dy * delta;
this.theta += this.dTheta * delta;
// Compute spline and convert to polar
var phi = this.frame % 7777 / 7777, i = 0, j = 1;
while (phi >= this.splineX[j]) i = j++;
var rho = interpolation(
this.splineY[i],
this.splineY[j],
(phi-this.splineX[i]) / (this.splineX[j]-this.splineX[i])
);
phi *= PI2;
outerStyle.left = this.x + rho * cos(phi) + 'px';
outerStyle.top = this.y + rho * sin(phi) + 'px';
innerStyle.transform = this.axis + this.theta + 'deg)';
return this.y > height+deviation;
};
}
function poof() {
if (!frame) {
// Append the container
document.body.appendChild(container);
// Add confetti
var theme = colorThemes[onlyOnKonami ? colorThemes.length * random()|0 : 0]
, count = 0;
(function addConfetto() {
if (onlyOnKonami && ++count > particles)
return timer = undefined;
var confetto = new Confetto(theme);
confetti.push(confetto);
container.appendChild(confetto.outer);
timer = setTimeout(addConfetto, spread * random());
})(0);
// Start the loop
var prev = undefined;
requestAnimationFrame(function loop(timestamp) {
var delta = prev ? timestamp - prev : 0;
prev = timestamp;
var height = $window.height();
for (var i = confetti.length-1; i >= 0; --i) {
if (confetti[i].update(height, delta)) {
container.removeChild(confetti[i].outer);
confetti.splice(i, 1);
}
}
if (timer || confetti.length)
return frame = requestAnimationFrame(loop);
// Cleanup
document.body.removeChild(container);
frame = undefined;
});
}
}
$window.keydown(function(event) {
pointer = konami[pointer] === event.which
? pointer+1
: +(event.which === konami[0]);
if (pointer === konami.length) {
pointer = 0;
poof();
}
});
if (!onlyOnKonami) poof();
});
Look inside Confetto() it's just using a <div> inside another <div> and giving it random width, height, 3D rotation, etc., you should be able to manipulate innerStyle and/or outerStyle to your liking there.
Try adding something like this to make it rounded:
innerStyle.borderRadius = '100%';
Try something like this to make it squared:
innerStyle.borderRadius = '0';
Or a combination:
innerStyle.borderRadius = '100% 0 0 100%';
You should be able to set any style property you need, by camel-casing the css name (.border for border, .borderBottom for border-bottom, .borderBottomColor for border-bottom-color, etc.). Check this list for ideas
I'm trying to give each of the falling objects a gradient to make them look like shiny gold tickets.
I have a Codepen
I forked the pen from another repo and all i've changed in the background colour and the ticket colour.
This is the part of the code that control the colour. How do I add the gradient?
var colorThemes = [
function() {
//return color(200 * random()|0, 200 * random()|0, 200 * random()|0);
return color(218,165,32);
}, function() {
var black = 200 * random()|0; return color(200, black, black);
}, function() {
var black = 200 * random()|0; return color(black, 200, black);
}, function() {
var black = 200 * random()|0; return color(black, black, 200);
}, function() {
return color(200, 100, 200 * random()|0);
}, function() {
return color(200 * random()|0, 200, 200);
}, function() {
var black = 256 * random()|0; return color(black, black, black);
}, function() {
return colorThemes[random() < .5 ? 1 : 2]();
}, function() {
return colorThemes[random() < .5 ? 3 : 5]();
}, function() {
return colorThemes[random() < .5 ? 2 : 4]();
}
];
function color(r, g, b) {
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
'use strict';
// If set to true, the user must press
// UP UP DOWN ODWN LEFT RIGHT LEFT RIGHT A B
// to trigger the confetti with a random color theme.
// Otherwise the confetti constantly falls.
var onlyOnKonami = false;
$(function() {
// Globals
var $window = $(window)
, random = Math.random
, cos = Math.cos
, sin = Math.sin
, PI = Math.PI
, PI2 = PI * 2
, timer = undefined
, frame = undefined
, confetti = [];
// Settings
var konami = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]
, pointer = 0;
var particles = 150
, spread = 10
, sizeMin = 3
, sizeMax = 40 - sizeMin
, eccentricity = 10
, deviation = 100
, dxThetaMin = -.1
, dxThetaMax = -dxThetaMin - dxThetaMin
, dyMin = .13
, dyMax = .18
, dThetaMin = .4
, dThetaMax = .7 - dThetaMin;
var colorThemes = [
function() {
//return color(200 * random()|0, 200 * random()|0, 200 * random()|0);
return color(218,165,32);
}, function() {
var black = 200 * random()|0; return color(200, black, black);
}, function() {
var black = 200 * random()|0; return color(black, 200, black);
}, function() {
var black = 200 * random()|0; return color(black, black, 200);
}, function() {
return color(200, 100, 200 * random()|0);
}, function() {
return color(200 * random()|0, 200, 200);
}, function() {
var black = 256 * random()|0; return color(black, black, black);
}, function() {
return colorThemes[random() < .5 ? 1 : 2]();
}, function() {
return colorThemes[random() < .5 ? 3 : 5]();
}, function() {
return colorThemes[random() < .5 ? 2 : 4]();
}
];
function color(r, g, b) {
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
// Cosine interpolation
function interpolation(a, b, t) {
return (1-cos(PI*t))/2 * (b-a) + a;
}
// Create a 1D Maximal Poisson Disc over [0, 1]
var radius = 1/eccentricity, radius2 = radius+radius;
function createPoisson() {
// domain is the set of points which are still available to pick from
// D = union{ [d_i, d_i+1] | i is even }
var domain = [radius, 1-radius], measure = 1-radius2, spline = [0, 1];
while (measure) {
var dart = measure * random(), i, l, interval, a, b, c, d;
// Find where dart lies
for (i = 0, l = domain.length, measure = 0; i < l; i += 2) {
a = domain[i], b = domain[i+1], interval = b-a;
if (dart < measure+interval) {
spline.push(dart += a-measure);
break;
}
measure += interval;
}
c = dart-radius, d = dart+radius;
// Update the domain
for (i = domain.length-1; i > 0; i -= 2) {
l = i-1, a = domain[l], b = domain[i];
// c---d c---d Do nothing
// c-----d c-----d Move interior
// c--------------d Delete interval
// c--d Split interval
// a------b
if (a >= c && a < d)
if (b > d) domain[l] = d; // Move interior (Left case)
else domain.splice(l, 2); // Delete interval
else if (a < c && b > c)
if (b <= d) domain[i] = c; // Move interior (Right case)
else domain.splice(i, 0, c, d); // Split interval
}
// Re-measure the domain
for (i = 0, l = domain.length, measure = 0; i < l; i += 2)
measure += domain[i+1]-domain[i];
}
return spline.sort();
}
// Create the overarching container
var container = document.createElement('div');
container.style.position = 'fixed';
container.style.top = '0';
container.style.left = '0';
container.style.width = '100%';
container.style.height = '0';
container.style.overflow = 'visible';
container.style.zIndex = '9999';
// Confetto constructor
function Confetto(theme) {
this.frame = 0;
this.outer = document.createElement('div');
this.inner = document.createElement('div');
this.outer.appendChild(this.inner);
var outerStyle = this.outer.style, innerStyle = this.inner.style;
outerStyle.position = 'absolute';
outerStyle.width = (sizeMin + sizeMax * random()) + 'px';
outerStyle.height = (sizeMin + sizeMax * random()) + 'px';
innerStyle.width = '100%';
innerStyle.height = '100%';
innerStyle.backgroundColor = theme();
outerStyle.perspective = '100px';
outerStyle.transform = 'rotate(' + (360 * random()) + 'deg)';
this.axis = 'rotate3D(' +
cos(360 * random()) + ',' +
cos(360 * random()) + ',0,';
this.theta = 360 * random();
this.dTheta = dThetaMin + dThetaMax * random();
innerStyle.transform = this.axis + this.theta + 'deg)';
this.x = $window.width() * random();
this.y = -deviation;
this.dx = sin(dxThetaMin + dxThetaMax * random());
this.dy = dyMin + dyMax * random();
outerStyle.left = this.x + 'px';
outerStyle.top = this.y + 'px';
// Create the periodic spline
this.splineX = createPoisson();
this.splineY = [];
for (var i = 1, l = this.splineX.length-1; i < l; ++i)
this.splineY[i] = deviation * random();
this.splineY[0] = this.splineY[l] = deviation * random();
this.update = function(height, delta) {
this.frame += delta;
this.x += this.dx * delta;
this.y += this.dy * delta;
this.theta += this.dTheta * delta;
// Compute spline and convert to polar
var phi = this.frame % 7777 / 7777, i = 0, j = 1;
while (phi >= this.splineX[j]) i = j++;
var rho = interpolation(
this.splineY[i],
this.splineY[j],
(phi-this.splineX[i]) / (this.splineX[j]-this.splineX[i])
);
phi *= PI2;
outerStyle.left = this.x + rho * cos(phi) + 'px';
outerStyle.top = this.y + rho * sin(phi) + 'px';
innerStyle.transform = this.axis + this.theta + 'deg)';
return this.y > height+deviation;
};
}
function poof() {
if (!frame) {
// Append the container
document.body.appendChild(container);
// Add confetti
var theme = colorThemes[onlyOnKonami ? colorThemes.length * random()|0 : 0]
, count = 0;
(function addConfetto() {
if (onlyOnKonami && ++count > particles)
return timer = undefined;
var confetto = new Confetto(theme);
confetti.push(confetto);
container.appendChild(confetto.outer);
timer = setTimeout(addConfetto, spread * random());
})(0);
// Start the loop
var prev = undefined;
requestAnimationFrame(function loop(timestamp) {
var delta = prev ? timestamp - prev : 0;
prev = timestamp;
var height = $window.height();
for (var i = confetti.length-1; i >= 0; --i) {
if (confetti[i].update(height, delta)) {
container.removeChild(confetti[i].outer);
confetti.splice(i, 1);
}
}
if (timer || confetti.length)
return frame = requestAnimationFrame(loop);
// Cleanup
document.body.removeChild(container);
frame = undefined;
});
}
}
$window.keydown(function(event) {
pointer = konami[pointer] === event.which
? pointer+1
: +(event.which === konami[0]);
if (pointer === konami.length) {
pointer = 0;
poof();
}
});
if (!onlyOnKonami) poof();
});
html {
height: 100%;
}
body {
background: #d09d42;
background: linear-gradient(to bottom, #efc466, #d09d42);
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You need to modify method Confetto() to change the color of the divI've added the following javascript after innerStyle.backgroundColor = theme():
function Confetto(){
//Code
innerStyle.backgroundColor = theme()
innerStyle.background = "linear-gradient(to right, " + theme() + " , yellow)";
innerStyle.border = "thick solid #FFFB00";
innerStyle.borderWidth = "thin";
//Rest of the code
}
Check out this :
// JavaScript source code
'use strict';
// If set to true, the user must press
// UP UP DOWN ODWN LEFT RIGHT LEFT RIGHT A B
// to trigger the confetti with a random color theme.
// Otherwise the confetti constantly falls.
var onlyOnKonami = false;
$(function () {
// Globals
var $window = $(window),
random = Math.random,
cos = Math.cos,
sin = Math.sin,
PI = Math.PI,
PI2 = PI * 2,
timer = undefined,
frame = undefined,
confetti = [];
// Settings
var konami = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65],
//var konami = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
pointer = 0;
var particles = 10,
spread = 10,
sizeMin = 3,
sizeMax = 40 - sizeMin,
eccentricity = 10,
deviation = 100,
dxThetaMin = -.1,
dxThetaMax = -dxThetaMin - dxThetaMin,
dyMin = .13,
dyMax = .18,
dThetaMin = .4,
dThetaMax = .7 - dThetaMin;
var colorThemes = [
function () {
//return color(200 * random()|0, 200 * random()|0, 200 * random()|0);
return color(218, 165, 32);
},
function () {
var black = 200 * random() | 0;
return color(200, black, black);
},
function () {
var black = 200 * random() | 0;
return color(black, 200, black);
},
function () {
var black = 200 * random() | 0;
return color(black, black, 200);
},
function () {
return color(200, 100, 200 * random() | 0);
},
function () {
return color(200 * random() | 0, 200, 200);
},
function () {
var black = 256 * random() | 0;
return color(black, black, black);
},
function () {
return colorThemes[random() < .5 ? 1 : 2]();
},
function () {
return colorThemes[random() < .5 ? 3 : 5]();
},
function () {
return colorThemes[random() < .5 ? 2 : 4]();
}
];
function color(r, g, b) {
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
// Cosine interpolation
function interpolation(a, b, t) {
return (1 - cos(PI * t)) / 2 * (b - a) + a;
}
// Create a 1D Maximal Poisson Disc over [0, 1]
var radius = 1 / eccentricity,
radius2 = radius + radius;
function createPoisson() {
// domain is the set of points which are still available to pick from
// D = union{ [d_i, d_i+1] | i is even }
var domain = [radius, 1 - radius],
measure = 1 - radius2,
spline = [0, 1];
while (measure) {
var dart = measure * random(),
i, l, interval, a, b, c, d;
// Find where dart lies
for (i = 0, l = domain.length, measure = 0; i < l; i += 2) {
a = domain[i], b = domain[i + 1], interval = b - a;
if (dart < measure + interval) {
spline.push(dart += a - measure);
break;
}
measure += interval;
}
c = dart - radius, d = dart + radius;
// Update the domain
for (i = domain.length - 1; i > 0; i -= 2) {
l = i - 1, a = domain[l], b = domain[i];
// c---d c---d Do nothing
// c-----d c-----d Move interior
// c--------------d Delete interval
// c--d Split interval
// a------b
if (a >= c && a < d)
if (b > d) domain[l] = d; // Move interior (Left case)
else domain.splice(l, 2); // Delete interval
else if (a < c && b > c)
if (b <= d) domain[i] = c; // Move interior (Right case)
else domain.splice(i, 0, c, d); // Split interval
}
// Re-measure the domain
for (i = 0, l = domain.length, measure = 0; i < l; i += 2)
measure += domain[i + 1] - domain[i];
}
return spline.sort();
}
// Create the overarching container
var container = document.createElement('div');
container.style.position = 'fixed';
container.style.top = '0';
container.style.left = '0';
container.style.width = '100%';
container.style.height = '0';
container.style.overflow = 'visible';
container.style.zIndex = '9999';
// Confetto constructor
function Confetto(theme) {
this.frame = 0;
this.outer = document.createElement('div');
this.inner = document.createElement('div');
this.outer.appendChild(this.inner);
var outerStyle = this.outer.style,
innerStyle = this.inner.style;
outerStyle.position = 'absolute';
outerStyle.width = (sizeMin + sizeMax * random()) + 'px';
outerStyle.height = (sizeMin + sizeMax * random()) + 'px';
innerStyle.width = '100%';
innerStyle.height = '100%';
var f = theme();
innerStyle.backgroundColor = theme();
innerStyle.background = "linear-gradient(to right, " + theme() + " , yellow)";
innerStyle.border = "thick solid #FFFB00";
innerStyle.borderWidth = "thin";
outerStyle.perspective = '100px';
outerStyle.transform = 'rotate(' + (360 * random()) + 'deg)';
this.axis = 'rotate3D(' +
cos(360 * random()) + ',' +
cos(360 * random()) + ',0,';
this.theta = 360 * random();
this.dTheta = dThetaMin + dThetaMax * random();
innerStyle.transform = this.axis + this.theta + 'deg)';
this.x = $window.width() * random();
this.y = -deviation;
this.dx = sin(dxThetaMin + dxThetaMax * random());
this.dy = dyMin + dyMax * random();
outerStyle.left = this.x + 'px';
outerStyle.top = this.y + 'px';
// Create the periodic spline
this.splineX = createPoisson();
this.splineY = [];
for (var i = 1, l = this.splineX.length - 1; i < l; ++i)
this.splineY[i] = deviation * random();
this.splineY[0] = this.splineY[l] = deviation * random();
this.update = function (height, delta) {
this.frame += delta;
this.x += this.dx * delta;
this.y += this.dy * delta;
this.theta += this.dTheta * delta;
// Compute spline and convert to polar
var phi = this.frame % 7777 / 7777,
i = 0,
j = 1;
while (phi >= this.splineX[j]) i = j++;
var rho = interpolation(
this.splineY[i],
this.splineY[j],
(phi - this.splineX[i]) / (this.splineX[j] - this.splineX[i])
);
phi *= PI2;
outerStyle.left = this.x + rho * cos(phi) + 'px';
outerStyle.top = this.y + rho * sin(phi) + 'px';
innerStyle.transform = this.axis + this.theta + 'deg)';
return this.y > height + deviation;
};
}
function poof() {
if (!frame) {
// Append the container
document.body.appendChild(container);
// Add confetti
var theme = colorThemes[onlyOnKonami ? colorThemes.length * random() | 0 : 0],
count = 0;
(function addConfetto() {
if (onlyOnKonami && ++count > particles)
return timer = undefined;
var confetto = new Confetto(theme);
confetti.push(confetto);
container.appendChild(confetto.outer);
timer = setTimeout(addConfetto, spread * random());
})(0);
// Start the loop
var prev = undefined;
requestAnimationFrame(function loop(timestamp) {
var delta = prev ? timestamp - prev : 0;
prev = timestamp;
var height = $window.height();
for (var i = confetti.length - 1; i >= 0; --i) {
if (confetti[i].update(height, delta)) {
container.removeChild(confetti[i].outer);
confetti.splice(i, 1);
}
}
if (timer || confetti.length)
return frame = requestAnimationFrame(loop);
// Cleanup
document.body.removeChild(container);
frame = undefined;
});
}
}
$window.keydown(function (event) {
pointer = konami[pointer] === event.which ?
pointer + 1 :
+(event.which === konami[0]);
if (pointer === konami.length) {
pointer = 0;
poof();
}
});
if (!onlyOnKonami) poof();
});
html {
height: 100%;
}
body {
background: #d09d42;
background: linear-gradient(to bottom, #efc466, #d09d42);
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
For the last step of this project, I want the growing circle to stop when it collides with another circle. The isOnCircle function already checks for this successfully when creating a new circle. However, when adding the condition !isOnCircle to my grow() function (line 61) it prevents any new circles from being added.
function grow() {
var a = circles[circles.length - 1];
if (!isOnCircle(a)){
a.radius += 1;
}}
Perhaps the circle is being created first, then in the check for collision, it's colliding with itself. Where else could I put the !isOnCircle check so that it gets checked at every radius increase and stops the grow function then?
check this
//set up canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var circles = [];
//create circle
function create(location) {
circles.push({
x: location.x,
y: location.y,
radius: 10,
color: '#' + Math.floor(Math.random() * 16777215).toString(16)
});
}
//figure out mouse position
var rect = document.getElementById("canvas").getBoundingClientRect();
// Get canvas offset on page
var offset = {
x: rect.left,
y: rect.top
};
function isOnCanvas(a) {
if ((a.x >= 0 && a.x <= rect.width) && (a.y >= 0 && a.y <= rect.height)) {
return true;
}
return false;
}
function isOnCircle(a) {
var i = 0,
l = circles.length,
x, y, d, c;
for (; i < l; ++i) {
c = circles[i];
x = a.x - c.x;
y = a.y - c.y;
d = (a.radius || 10) + c.radius;
if (x * x + y * y <= d * d) {
return true;
}
}
return false;
}
// draw all circles
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < circles.length; i++) {
var p = circles[i];
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, 2 * Math.PI);
ctx.fillStyle = p.color;
ctx.fill();
}
}
//make last drawn circle 1px bigger
function grow() {
var a = circles[circles.length - 1];
a.radius += 1;
}
//find percentage of canvas filled in
var totalSpace = canvas.width * canvas.height;
var totalFilled = function () {
total = 0;
for (var i = 0; i < circles.length; i++) {
var p = circles[i];
total += Math.PI * Math.pow(p.radius, 2);
}
return total;
console.log(total);
}
function findPercentage() {
return (totalFilled() / totalSpace) * 100;
}
function updateInfo() {
percentage = findPercentage();
document.getElementById("percentage").innerHTML = "You've filled in " + percentage.toFixed(1) + "%";
}
//do all the stuff
var animate = function () {
grow();
draw();
updateInfo();
}
//put this outside function so we can stop it later
var growLoop;
window.onmousedown = function (e) {
// get event location on page offset by canvas location
var location = {
x: e.pageX - offset.x,
y: e.pageY - offset.y
};
if (isOnCanvas(location) && !isOnCircle(location)) {
create(location);
draw();
updateInfo();
growLoop = setInterval(animate, 100);
}
};
window.onmouseup = function () {
clearInterval(growLoop);
}
window.onmouseout = function () {
clearInterval(growLoop);
}
it's colliding with itself.
Probably. You definitely should avoid that in the collision detection:
function isOnCircle(a) {
var l = circles.length,
x, y, d, c;
for (var i = 0; i < l; ++i) {
c = circles[i];
if (a == c) // add these
continue; // two lines!
x = a.x - c.x;
y = a.y - c.y;
d = (a.radius || 10) + c.radius;
if (x * x + y * y <= d * d) {
return true;
}
}
return false;
}
It is colliding with itself. Since you know the current circle will always be the last one in circles you can modify isOnCircle like this:
l = circles.length - 1,
so that it won't check against the current circle.
http://jsfiddle.net/SeAGU/91/