@tsparticles/engine
Version:
Easily create highly customizable particle, confetti and fireworks 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.
113 lines (112 loc) • 4.42 kB
JavaScript
import { ErrorCodes, getErrorMessage } from "../Utils/ErrorUtils.js";
import { getCanvasFromContainer, getDataFromUrl, getDomContainer, itemFromSingleOrMultiple } from "../Utils/Utils.js";
import { loadMinIndex, loadRandomFactor, none, one, removeDeleteCount, removeMinIndex } from "./Utils/Constants.js";
import { EventDispatcher } from "../Utils/EventDispatcher.js";
import { PluginManager } from "./Utils/PluginManager.js";
import { getRandom } from "../Utils/MathUtils.js";
export class Engine {
pluginManager = new PluginManager(this);
#domArray = [];
#eventDispatcher = new EventDispatcher();
#initialized = false;
#loadSequence = 0;
#loadSequences = new Map();
get items() {
return this.#domArray;
}
get version() {
return "4.5.3";
}
addEventListener(type, listener) {
this.#eventDispatcher.addEventListener(type, listener);
}
checkVersion(pluginVersion) {
if (this.version === pluginVersion) {
return;
}
throw new Error(getErrorMessage(ErrorCodes.engineVersionMismatch, this.version, pluginVersion));
}
dispatchEvent(type, args) {
this.#eventDispatcher.dispatchEvent(type, args);
}
async init() {
if (this.#initialized) {
return;
}
await this.pluginManager.init();
this.#initialized = true;
}
item(index) {
const items = this.items, item = items[index];
if (item?.destroyed) {
items.splice(index, removeDeleteCount);
return;
}
return item;
}
async load(params) {
let domSourceElement;
if (typeof HTMLElement !== "undefined" && params.element instanceof HTMLElement) {
domSourceElement = params.element;
}
const id = params.id ?? domSourceElement?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, loadSequence = ++this.#loadSequence;
this.#loadSequences.set(id, loadSequence);
try {
await this.init();
const { Container } = await import("./Container.js"), { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options;
if (this.#loadSequences.get(id) !== loadSequence) {
return undefined;
}
const currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container({
dispatchCallback: (eventType, args) => {
this.dispatchEvent(eventType, args);
},
id,
onDestroy: (remove) => {
if (!remove) {
return;
}
const mainArr = this.items, idx = mainArr.indexOf(newItem);
if (idx >= removeMinIndex) {
mainArr.splice(idx, removeDeleteCount);
}
},
pluginManager: this.pluginManager,
sourceOptions: currentOptions,
});
if (oldIndex >= loadMinIndex) {
const old = this.item(oldIndex), deleteCount = old ? one : none;
if (old && !old.destroyed) {
old.destroy(false);
}
items.splice(oldIndex, deleteCount, newItem);
}
else {
items.push(newItem);
}
const sourceCanvas = typeof OffscreenCanvas !== "undefined" && params.element instanceof OffscreenCanvas
? params.element
: getCanvasFromContainer(getDomContainer(id, domSourceElement));
newItem.canvas.loadCanvas(sourceCanvas);
await newItem.start();
if (newItem.destroyed) {
return undefined;
}
return newItem;
}
finally {
if (this.#loadSequences.get(id) === loadSequence) {
this.#loadSequences.delete(id);
}
}
}
async refresh(refresh = true) {
if (!refresh) {
return;
}
await Promise.all(this.items.map(t => t.refresh()));
}
removeEventListener(type, listener) {
this.#eventDispatcher.removeEventListener(type, listener);
}
}