(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "./Utils/InteractionManager", "./Particle", "./Utils/Point", "./Utils/QuadTree", "./Utils/Rectangle", "../Utils/NumberUtils"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Particles = void 0; const InteractionManager_1 = require("./Utils/InteractionManager"); const Particle_1 = require("./Particle"); const Point_1 = require("./Utils/Point"); const QuadTree_1 = require("./Utils/QuadTree"); const Rectangle_1 = require("./Utils/Rectangle"); const NumberUtils_1 = require("../Utils/NumberUtils"); class Particles { constructor(engine, container) { this.container = container; this._engine = engine; this.nextId = 0; this.array = []; this.zArray = []; this.pool = []; this.limit = 0; this.needsSort = false; this.lastZIndex = 0; this.interactionManager = new InteractionManager_1.InteractionManager(this._engine, container); const canvasSize = this.container.canvas.size; this.quadTree = new QuadTree_1.QuadTree(new Rectangle_1.Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, (canvasSize.width * 3) / 2, (canvasSize.height * 3) / 2), 4); this.movers = this._engine.plugins.getMovers(container, true); this.updaters = this._engine.plugins.getUpdaters(container, true); } get count() { return this.array.length; } addManualParticles() { const container = this.container, options = container.actualOptions; for (const particle of options.manualParticles) { this.addParticle((0, NumberUtils_1.calcPositionFromSize)({ size: container.canvas.size, position: particle.position, }), particle.options); } } addParticle(position, overrideOptions, group, initializer) { const container = this.container, options = container.actualOptions, limit = options.particles.number.limit; if (limit > 0) { const countToRemove = this.count + 1 - limit; if (countToRemove > 0) { this.removeQuantity(countToRemove); } } return this._pushParticle(position, overrideOptions, group, initializer); } clear() { this.array = []; this.zArray = []; } destroy() { this.array = []; this.zArray = []; this.movers = []; this.updaters = []; } async draw(delta) { const container = this.container, canvasSize = this.container.canvas.size; this.quadTree = new QuadTree_1.QuadTree(new Rectangle_1.Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, (canvasSize.width * 3) / 2, (canvasSize.height * 3) / 2), 4); container.canvas.clear(); await this.update(delta); if (this.needsSort) { this.zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id); this.lastZIndex = this.zArray[this.zArray.length - 1].position.z; this.needsSort = false; } for (const [, plugin] of container.plugins) { container.canvas.drawPlugin(plugin, delta); } for (const p of this.zArray) { p.draw(delta); } } handleClickMode(mode) { this.interactionManager.handleClickMode(mode); } init() { var _a; const container = this.container, options = container.actualOptions; this.lastZIndex = 0; this.needsSort = false; let handled = false; this.updaters = this._engine.plugins.getUpdaters(container, true); this.interactionManager.init(); for (const [, plugin] of container.plugins) { if (plugin.particlesInitialization !== undefined) { handled = plugin.particlesInitialization(); } if (handled) { break; } } this.interactionManager.init(); for (const [, pathGenerator] of container.pathGenerators) { pathGenerator.init(container); } this.addManualParticles(); if (!handled) { for (const group in options.particles.groups) { const groupOptions = options.particles.groups[group]; for (let i = this.count, j = 0; j < ((_a = groupOptions.number) === null || _a === void 0 ? void 0 : _a.value) && i < options.particles.number.value; i++, j++) { this.addParticle(undefined, groupOptions, group); } } for (let i = this.count; i < options.particles.number.value; i++) { this.addParticle(); } } } push(nb, mouse, overrideOptions, group) { this.pushing = true; for (let i = 0; i < nb; i++) { this.addParticle(mouse === null || mouse === void 0 ? void 0 : mouse.position, overrideOptions, group); } this.pushing = false; } async redraw() { this.clear(); this.init(); await this.draw({ value: 0, factor: 0 }); } remove(particle, group, override) { this.removeAt(this.array.indexOf(particle), undefined, group, override); } removeAt(index, quantity = 1, group, override) { if (index < 0 || index > this.count) { return; } let deleted = 0; for (let i = index; deleted < quantity && i < this.count; i++) { const particle = this.array[i]; if (!particle || particle.group !== group) { continue; } particle.destroy(override); this.array.splice(i--, 1); const zIdx = this.zArray.indexOf(particle); this.zArray.splice(zIdx, 1); this.pool.push(particle); deleted++; this._engine.dispatchEvent("particleRemoved", { container: this.container, data: { particle, }, }); } } removeQuantity(quantity, group) { this.removeAt(0, quantity, group); } setDensity() { const options = this.container.actualOptions; for (const group in options.particles.groups) { this._applyDensity(options.particles.groups[group], 0, group); } this._applyDensity(options.particles, options.manualParticles.length); } async update(delta) { var _a, _b; const container = this.container, particlesToDelete = []; for (const [, pathGenerator] of container.pathGenerators) { pathGenerator.update(); } for (const [, plugin] of container.plugins) { (_a = plugin.update) === null || _a === void 0 ? void 0 : _a.call(plugin, delta); } for (const particle of this.array) { const resizeFactor = container.canvas.resizeFactor; if (resizeFactor && !particle.ignoresResizeRatio) { particle.position.x *= resizeFactor.width; particle.position.y *= resizeFactor.height; particle.initialPosition.x *= resizeFactor.width; particle.initialPosition.y *= resizeFactor.height; } particle.ignoresResizeRatio = false; await this.interactionManager.reset(particle); for (const [, plugin] of this.container.plugins) { if (particle.destroyed) { break; } (_b = plugin.particleUpdate) === null || _b === void 0 ? void 0 : _b.call(plugin, particle, delta); } for (const mover of this.movers) { if (mover.isEnabled(particle)) { mover.move(particle, delta); } } if (particle.destroyed) { particlesToDelete.push(particle); continue; } this.quadTree.insert(new Point_1.Point(particle.getPosition(), particle)); } for (const particle of particlesToDelete) { this.remove(particle); } await this.interactionManager.externalInteract(delta); for (const particle of this.array) { for (const updater of this.updaters) { updater.update(particle, delta); } if (!particle.destroyed && !particle.spawning) { await this.interactionManager.particlesInteract(particle, delta); } } delete container.canvas.resizeFactor; } _applyDensity(options, manualCount, group) { var _a; if (!((_a = options.number.density) === null || _a === void 0 ? void 0 : _a.enable)) { return; } const numberOptions = options.number, densityFactor = this._initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit > 0 ? numberOptions.limit : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount, particlesCount = Math.min(this.count, this.array.filter((t) => t.group === group).length); this.limit = numberOptions.limit * densityFactor; if (particlesCount < particlesNumber) { this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group); } else if (particlesCount > particlesNumber) { this.removeQuantity(particlesCount - particlesNumber, group); } } _initDensityFactor(densityOptions) { const container = this.container; if (!container.canvas.element || !densityOptions.enable) { return 1; } const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio; return (canvas.width * canvas.height) / (densityOptions.factor * pxRatio ** 2 * densityOptions.area); } _pushParticle(position, overrideOptions, group, initializer) { try { let particle = this.pool.pop(); if (particle) { particle.init(this.nextId, position, overrideOptions, group); } else { particle = new Particle_1.Particle(this._engine, this.nextId, this.container, position, overrideOptions, group); } let canAdd = true; if (initializer) { canAdd = initializer(particle); } if (!canAdd) { return; } this.array.push(particle); this.zArray.push(particle); this.nextId++; this._engine.dispatchEvent("particleAdded", { container: this.container, data: { particle, }, }); return particle; } catch (e) { console.warn(`error adding particle: ${e}`); return; } } } exports.Particles = Particles; });