277 lines
12 KiB
JavaScript
277 lines
12 KiB
JavaScript
(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;
|
|
});
|