tsparticles-confetti
Version:
Easily create highly customizable particle animations and use them as animated backgrounds for your website. Ready to use components available also for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.
301 lines (300 loc) • 9.56 kB
JavaScript
import { isSsr, isString, tsParticles, } from "tsparticles-engine";
import { ConfettiOptions } from "./ConfettiOptions";
import { loadBasic } from "tsparticles-basic";
import { loadCardsShape } from "tsparticles-shape-cards";
import { loadEmittersPlugin } from "tsparticles-plugin-emitters";
import { loadHeartShape } from "tsparticles-shape-heart";
import { loadImageShape } from "tsparticles-shape-image";
import { loadLifeUpdater } from "tsparticles-updater-life";
import { loadMotionPlugin } from "tsparticles-plugin-motion";
import { loadPolygonShape } from "tsparticles-shape-polygon";
import { loadRollUpdater } from "tsparticles-updater-roll";
import { loadRotateUpdater } from "tsparticles-updater-rotate";
import { loadSquareShape } from "tsparticles-shape-square";
import { loadStarShape } from "tsparticles-shape-star";
import { loadTextShape } from "tsparticles-shape-text";
import { loadTiltUpdater } from "tsparticles-updater-tilt";
import { loadWobbleUpdater } from "tsparticles-updater-wobble";
let initialized = false;
let initializing = false;
const ids = new Map();
async function initPlugins(engine) {
if (initialized) {
return;
}
if (initializing) {
return new Promise((resolve) => {
const interval = setInterval(() => {
if (!initialized) {
return;
}
clearInterval(interval);
resolve();
}, 100);
});
}
initializing = true;
await loadBasic(engine);
await loadEmittersPlugin(engine);
await loadMotionPlugin(engine);
await loadCardsShape(engine);
await loadHeartShape(engine);
await loadImageShape(engine);
await loadPolygonShape(engine);
await loadSquareShape(engine);
await loadStarShape(engine);
await loadTextShape(engine);
await loadRotateUpdater(engine);
await loadLifeUpdater(engine);
await loadRollUpdater(engine);
await loadTiltUpdater(engine);
await loadWobbleUpdater(engine);
initializing = false;
initialized = true;
}
async function setConfetti(params) {
const actualOptions = new ConfettiOptions();
actualOptions.load(params.options);
let container;
const fpsLimit = 120, opacitySpeed = (actualOptions.ticks * 1000) / (3600 * fpsLimit);
if (ids.has(params.id)) {
container = ids.get(params.id);
if (container && !container.destroyed) {
const alias = container;
if (alias.addEmitter) {
alias.addEmitter({
startCount: actualOptions.count,
position: actualOptions.position,
size: {
width: 0,
height: 0,
},
rate: {
delay: 0,
quantity: 0,
},
life: {
duration: 0.1,
count: 1,
},
particles: {
color: {
value: actualOptions.colors,
},
shape: {
type: actualOptions.shapes,
options: actualOptions.shapeOptions,
},
life: {
count: 1,
},
opacity: {
value: { min: 0, max: 1 },
animation: {
enable: true,
sync: true,
speed: opacitySpeed,
startValue: "max",
destroy: "min",
},
},
size: {
value: 5 * actualOptions.scalar,
},
move: {
angle: {
value: actualOptions.spread,
offset: 0,
},
drift: {
min: -actualOptions.drift,
max: actualOptions.drift,
},
gravity: {
acceleration: actualOptions.gravity * 9.81,
},
speed: actualOptions.startVelocity * 3,
decay: 1 - actualOptions.decay,
direction: -actualOptions.angle,
},
},
});
return;
}
}
}
const particlesOptions = {
fullScreen: {
enable: !params.canvas,
zIndex: actualOptions.zIndex,
},
fpsLimit: 120,
particles: {
number: {
value: 0,
},
color: {
value: actualOptions.colors,
},
shape: {
type: actualOptions.shapes,
options: actualOptions.shapeOptions,
},
opacity: {
value: { min: 0, max: 1 },
animation: {
enable: true,
sync: true,
speed: opacitySpeed,
startValue: "max",
destroy: "min",
},
},
size: {
value: 5 * actualOptions.scalar,
},
links: {
enable: false,
},
life: {
count: 1,
},
move: {
angle: {
value: actualOptions.spread,
offset: 0,
},
drift: {
min: -actualOptions.drift,
max: actualOptions.drift,
},
enable: true,
gravity: {
enable: true,
acceleration: actualOptions.gravity * 9.81,
},
speed: actualOptions.startVelocity * 3,
decay: 1 - actualOptions.decay,
direction: -actualOptions.angle,
random: true,
straight: false,
outModes: {
default: "none",
bottom: "destroy",
},
},
rotate: {
value: {
min: 0,
max: 360,
},
direction: "random",
animation: {
enable: true,
speed: 60,
},
},
tilt: {
direction: "random",
enable: true,
value: {
min: 0,
max: 360,
},
animation: {
enable: true,
speed: 60,
},
},
roll: {
darken: {
enable: true,
value: 25,
},
enable: true,
speed: {
min: 15,
max: 25,
},
},
wobble: {
distance: 30,
enable: true,
speed: {
min: -15,
max: 15,
},
},
},
detectRetina: true,
motion: {
disable: actualOptions.disableForReducedMotion,
},
emitters: {
name: "confetti",
startCount: actualOptions.count,
position: actualOptions.position,
size: {
width: 0,
height: 0,
},
rate: {
delay: 0,
quantity: 0,
},
life: {
duration: 0.1,
count: 1,
},
},
};
container = await tsParticles.load({ id: params.id, element: params.canvas, options: particlesOptions });
ids.set(params.id, container);
return container;
}
export async function confetti(idOrOptions, confettiOptions) {
await initPlugins(tsParticles);
let options;
let id;
if (isString(idOrOptions)) {
id = idOrOptions;
options = confettiOptions ?? {};
}
else {
id = "confetti";
options = idOrOptions;
}
return setConfetti({
id,
options,
});
}
confetti.create = async (canvas, options) => {
if (!canvas) {
return confetti;
}
await initPlugins(tsParticles);
const id = canvas.getAttribute("id") || "confetti";
canvas.setAttribute("id", id);
return async (idOrOptions, confettiOptions) => {
let subOptions;
let subId;
if (isString(idOrOptions)) {
subId = idOrOptions;
subOptions = confettiOptions ?? options;
}
else {
subId = id;
subOptions = idOrOptions;
}
return setConfetti({
id: subId,
canvas,
options: subOptions,
});
};
};
confetti.version = tsParticles.version;
if (!isSsr()) {
window.confetti = confetti;
}