//import { Fireworks } from '/js/fireworks-js@2.x/dist/fireworks.js';
//console.log(Fireworks);
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class EffectsObj
{
constructor() {
this.particlesContainer = null;
this.fireworksObj = null;
}
init() {
window.myConfetti = confetti.create(document.getElementById('myConfettiCanvas'), {
resize: true,
useWorker: true
});
// Force this canvas on top of Bootstrap modal
let myConfettiObj = $('#myConfettiCanvas');
if (myConfettiObj.length === 0) {
$('body').append('');
myConfettiObj = $('#myConfettiCanvas');
}
const c = document.getElementById('myConfettiCanvas');
c.style.position = 'fixed';
c.style.top = 0;
c.style.left = 0;
c.style.zIndex = 999999; // OVER the modal
c.style.pointerEvents = 'none';
// fireworks
/*
if ($("#tsparticles").length === 0) {
$("body").append(`
`);
}
// Load the tsParticles container with configuration
tsParticles.load("tsparticles", {
background: {
color: "transparent"
},
particles: {
number: { value: 0 }, // No initial particles
color: { value: ["#ff0000", "#ffff00", "#00ffff", "#ffffff"] },
shape: { type: "circle" },
opacity: { value: { min: 0.6, max: 1 } },
size: { value: { min: 2, max: 4 } },
move: { enable: true, speed: { min: 10, max: 25 }, direction: "none", outModes: { default: "destroy" } },
life: { count: 1, duration: { value: 2 } }
},
detectRetina: true
}).then((loadedContainer) => {
this.particlesContainer = loadedContainer;
console.log(this.particlesContainer.version);
console.log("Particles container initialized:", this.particlesContainer);
});*/
// Once the container is initialized, you can now safely add emitters
//console.log("Particles container initialized:", this.particlesContainer);
//console.log(this.particlesContainer.version);
}
confetti(obj) {
/*
const modalConfetti = confetti.create(
document.getElementById('modalConfetti'),
{
resize: true,
useWorker: true
}
)*/
let currObj = $(obj);
if (currObj.data('target-obj')) {
currObj = $(currObj.data('target-obj'));
}
const offset = currObj.offset();
const width = currObj.outerWidth();
const height = currObj.outerHeight();
// Convert to confetti origin (0–1 range)
const origin = {
//x: (offset.left + width / 2) / $(window).width(),
//y: (offset.top + height / 2) / $(window).height()
x: (offset.left + width / 2) / $(window).width(),
y: (offset.top + height / 2) / $(window).height()
};
confetti({
particleCount: 200,
spread: 90,
zIndex: 999999,
origin: origin
});
/*
setTimeout(() => {
const canvas =
document.querySelector("canvas.confetti-canvas");
if (canvas) {
canvas.style.position = "fixed";
canvas.style.zIndex = "999999";
canvas.style.pointerEvents = "none"; // so it doesn't block clicks
}
}, 0);*/
}
confettiStars(obj) {
let currObj = $(obj);
if (currObj.data('target-obj')) {
currObj = $(currObj.data('target-obj'));
}
const offset = currObj.offset();
const width = currObj.outerWidth();
const height = currObj.outerHeight();
// Convert to confetti origin (0–1 range)
const origin = {
x: (offset.left + width / 2) / $(window).width(),
y: (offset.top + height / 2) / $(window).height()
};
var defaults = {
spread: 360,
ticks: 50,
gravity: 0,
decay: 0.94,
startVelocity: 30,
zIndex: 999999,
colors: ['FFE400', 'FFBD00', 'E89400', 'FFCA6C', 'FDFFB8']
};
function shoot() {
confetti({
...defaults,
particleCount: 40,
scalar: 1.2,
shapes: ['star'],
origin: origin
});
confetti({
...defaults,
particleCount: 10,
scalar: 0.75,
shapes: ['circle'],
origin: origin
});
}
setTimeout(shoot, 0);
setTimeout(shoot, 100);
setTimeout(shoot, 200);
setTimeout(() => {
const canvas =
document.querySelector("canvas.confetti-canvas");
if (canvas) {
canvas.style.position = "fixed";
canvas.style.zIndex = "999999";
canvas.style.pointerEvents = "none"; // so it doesn't block clicks
}
}, 0);
}
confettiSmiley(obj) {
let currObj = $(obj);
if (currObj.data('target-obj')) {
currObj = $(currObj.data('target-obj'));
}
const offset = currObj.offset();
const width = currObj.outerWidth();
const height = currObj.outerHeight();
// Convert to confetti origin (0–1 range)
const origin = {
x: (offset.left + width / 2) / $(window).width(),
y: (offset.top + height / 2) / $(window).height()
};
var scalar = 2;
var unicorn = confetti.shapeFromText({ text: '🦄', scalar });
var smiley = confetti.shapeFromText({ text: '😀', scalar });
var defaults = {
spread: 360,
ticks: 60,
gravity: 0,
decay: 0.9,
startVelocity: 20,
shapes: [smiley, unicorn, smiley],
zIndex: 9999999,
origin: origin,
scalar
};
function shoot() {
confetti({
...defaults,
particleCount: 30
});
confetti({
...defaults,
particleCount: 5,
flat: true
});
confetti({
...defaults,
particleCount: 15,
scalar: scalar / 2,
shapes: ['circle']
});
}
setTimeout(shoot, 0);
setTimeout(shoot, 100);
setTimeout(shoot, 200);
}
fireworks(obj) {
let currObj = $(obj);
if (currObj.data('target-obj')) {
currObj = $(currObj.data('target-obj'));
}
const offset = currObj.offset();
const width = currObj.outerWidth();
const height = currObj.outerHeight();
// Convert to confetti origin (0–1 range)
const origin = {
x: (offset.left + width / 2) / $(window).width(),
y: (offset.top + height / 2) / $(window).height()
};
// Convert pixel coordinates to percentage (required by tsParticles)
const xPercent = (obj.x / window.innerWidth) * 100;
const yPercent = (obj.y / window.innerHeight) * 100;
// Initialize library
if (!this.fireworksObj) {
if ($('#fireworks-overlay').length === 0) {
$('body').append('');
}
const container = document.getElementById('fireworks-overlay');
this.fireworksObj = new Fireworks.Fireworks(container, {
autoresize: true,
opacity: 0.5,
acceleration: 1.05,
friction: 0.98,
gravity: 1.5,
particles: 100,
traceLength: 3,
explosion: 7,
// --- THESE TWO LINES STOP AUTO-LAUNCHING ---
//intensity: 0,
//delay: { min: 0, max: 0 }
});
this.fireworksObj.start();
}
let btn = currObj[0];
const rect = btn.getBoundingClientRect();
// Calculate center of button
const centerX = rect.left + rect.width / 2;
const startY = rect.top;
// Convert X pixel to percentage for the library (0-100)
const xPct = (centerX / window.innerWidth) * 100;
/*
this.fireworksObj.launch(4, {
// The explosion destination (above the button)
x: centerX + (Math.random() * 200 - 100),
y: startY - (200 + Math.random() * 300),
// The starting point (exactly at the button)
rocketsPoint: {
min: xPct,
max: xPct
}
});*/
// A helper function to save space
const shoot = (delayMs) => {
setTimeout(() => {
this.fireworksObj.launch(1, {
x: centerX + (Math.random() * 200 - 100), // Random spread
y: startY - (200 + Math.random() * 300), // Random height
rocketsPoint: {
min: xPct,
max: xPct
}
});
}, delayMs);
};
// Launch 4 fireworks at different times (in milliseconds)
shoot(0); // Immediate
shoot(400); // 0.4 seconds later
shoot(800); // 0.8 seconds later
shoot(1200); // 1.2 seconds later
/*
for (let iterator = 0; iterator < 5; iterator ++) {
// Launch rocket
let countLaunch = 0;
console.log(countLaunch);
setTimeout(function() {
this.fireworksObj.launch(4, {
// The explosion destination (above the button)
x: centerX + (Math.random() * 200 - 100),
y: startY - (200 + Math.random() * 300),
// The starting point (exactly at the button)
rocketsPoint: {
min: xPct,
max: xPct
}
});
countLaunch ++;
}, Math.random() * (2000 - 500) + 500);
}*/
}
fireworksOld(obj) {
let currObj = $(obj);
if (currObj.data('target-obj')) {
currObj = $(currObj.data('target-obj'));
}
const offset = currObj.offset();
const width = currObj.outerWidth();
const height = currObj.outerHeight();
// Convert to confetti origin (0–1 range)
const origin = {
x: (offset.left + width / 2) / $(window).width(),
y: (offset.top + height / 2) / $(window).height()
};
// Convert pixel coordinates to percentage (required by tsParticles)
const xPercent = (obj.x / window.innerWidth) * 100;
const yPercent = (obj.y / window.innerHeight) * 100;
// Load the particles effect
// Add an emitter at the specified position
console.log(this.particlesContainer.version);
console.log(this.particlesContainer);
this.particlesContainer.addEmitter({
position: { x: xPercent, y: yPercent },
rate: { quantity: 0, delay: 0 }, // Single burst
life: { count: 1, duration: 0.1 }, // Single burst duration
emitters: { direction: "none" },
burst: { count: 80, delay: 0 } // Number of particles in the burst
});
}
async runEffect(obj, single) {
let jObj = $(obj);
let effect = jObj.data('effect');
let effects = typeof single == 'boolean' && single === true ? null : jObj.data('effects');
let effectArray = new Array();
if (typeof effects == 'string' && effects.length > 0) {
effectArray = effects.split(',');
} else if (typeof effect == 'string' || typeof effect == 'number') {
effectArray.push(effect);
}
for (const effectIndex in effectArray) {
let effectId = parseInt(effectArray[effectIndex]);
console.log(effectIndex);
switch (effectId) {
case 1:
this.confetti(obj);
break;
case 2:
this.confettiStars(obj);
break;
case 3:
this.confettiSmiley(obj);
break;
case 4:
this.fireworks(obj);
break;
}
await this.sleep(2000);
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
class ShoutOut
{
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
chooseEffect(obj) {
let jObj = $(obj);
$('.btn-effect').not(obj).addClass('btn-outline-secondary');
$('.btn-effect').not(obj).removeClass('btn-secondary').removeClass('effect-selected');
jObj.addClass('btn-secondary').addClass('effect-selected');
jObj.removeClass('btn-outline-secondary');
}
saveEffect(obj) {
let jObj = $(obj);
let shoutOptCont = jObj.closest('.shout-out-opt');
let effectSelected = shoutOptCont.find('.effect-selected');
if (!effectSelected.length) {
let tooltip = bootstrap.Tooltip.getInstance(jObj);
if (tooltip) {
tooltip.dispose();
}
tooltip = new bootstrap.Tooltip(jObj, {
title: jObj.data('error-tip'),
trigger: 'manual',
customClass: 'error-tooltip',
placement: 'top'
})
tooltip.show();
setTimeout(function() {
tooltip.hide();
}, 3000);
return;
}
let effect = effectSelected.data('effect');
let athleteId = jObj.data('athlete-id');
// saved
$.ajax({
url: '/site/save-effect',
method: 'POST',
data: {athleteId: athleteId, effect: effect},
dataType: 'json',
success: function(data) {
if (data.success) {
lightBoxObject.fillContent('Saved Shoutout Successfully!', '');
}
}
});
}
payEffect(obj) {
let jObj = $(obj);
let shoutOptCont = jObj.closest('.shout-out-opt');
let effectSelected = shoutOptCont.find('.effect-selected');
if (!effectSelected.length) {
let tooltip = bootstrap.Tooltip.getInstance(jObj);
if (tooltip) {
tooltip.dispose();
}
tooltip = new bootstrap.Tooltip(jObj, {
title: jObj.data('error-tip'),
trigger: 'manual',
customClass: 'error-tooltip',
placement: 'top'
})
tooltip.show();
setTimeout(function() {
tooltip.hide();
}, 3000);
return;
}
let athleteId = jObj.data('athlete-id');
let effect = effectSelected.data('effect');
window.location = '/payment/checkout?item=effect&effect=' + effect + '&athleteId=' + athleteId;
}
}
let EffectsObject;
let ShoutOutObject;
$(document).ready(function(){
EffectsObject = new EffectsObj();
EffectsObject.init();
ShoutOutObject = new ShoutOut();
})