@tsparticles/engine 4.0.0-beta.0 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/155.min.js +1 -0
  2. package/README.md +0 -21
  3. package/browser/Core/CanvasManager.js +303 -0
  4. package/browser/Core/Container.js +61 -34
  5. package/browser/Core/Engine.js +26 -138
  6. package/browser/Core/Particle.js +29 -28
  7. package/{cjs/Core/Particles.js → browser/Core/ParticlesManager.js} +27 -57
  8. package/browser/Core/RenderManager.js +303 -0
  9. package/browser/Core/Retina.js +3 -8
  10. package/browser/Core/Utils/PluginManager.js +145 -0
  11. package/browser/Options/Classes/Options.js +7 -7
  12. package/browser/Options/Classes/Particles/ParticlesOptions.js +5 -5
  13. package/browser/Types/CanvasContextType.js +1 -0
  14. package/browser/Utils/CanvasUtils.js +1 -1
  15. package/browser/Utils/ColorUtils.js +21 -21
  16. package/browser/Utils/LogUtils.js +1 -0
  17. package/browser/Utils/OptionsUtils.js +2 -2
  18. package/cjs/Core/CanvasManager.js +303 -0
  19. package/cjs/Core/Container.js +61 -34
  20. package/cjs/Core/Engine.js +26 -138
  21. package/cjs/Core/Particle.js +29 -28
  22. package/{esm/Core/Particles.js → cjs/Core/ParticlesManager.js} +27 -57
  23. package/cjs/Core/RenderManager.js +303 -0
  24. package/cjs/Core/Retina.js +3 -8
  25. package/cjs/Core/Utils/PluginManager.js +145 -0
  26. package/cjs/Options/Classes/Options.js +7 -7
  27. package/cjs/Options/Classes/Particles/ParticlesOptions.js +5 -5
  28. package/cjs/Types/CanvasContextType.js +1 -0
  29. package/cjs/Utils/CanvasUtils.js +1 -1
  30. package/cjs/Utils/ColorUtils.js +21 -21
  31. package/cjs/Utils/LogUtils.js +1 -0
  32. package/cjs/Utils/OptionsUtils.js +2 -2
  33. package/dist_browser_Core_Container_js.js +24 -14
  34. package/esm/Core/CanvasManager.js +303 -0
  35. package/esm/Core/Container.js +61 -34
  36. package/esm/Core/Engine.js +26 -138
  37. package/esm/Core/Particle.js +29 -28
  38. package/{browser/Core/Particles.js → esm/Core/ParticlesManager.js} +27 -57
  39. package/esm/Core/RenderManager.js +303 -0
  40. package/esm/Core/Retina.js +3 -8
  41. package/esm/Core/Utils/PluginManager.js +145 -0
  42. package/esm/Options/Classes/Options.js +7 -7
  43. package/esm/Options/Classes/Particles/ParticlesOptions.js +5 -5
  44. package/esm/Types/CanvasContextType.js +1 -0
  45. package/esm/Utils/CanvasUtils.js +1 -1
  46. package/esm/Utils/ColorUtils.js +21 -21
  47. package/esm/Utils/LogUtils.js +1 -0
  48. package/esm/Utils/OptionsUtils.js +2 -2
  49. package/package.json +1 -1
  50. package/report.html +84 -29
  51. package/tsparticles.engine.js +18 -8
  52. package/tsparticles.engine.min.js +2 -2
  53. package/types/Core/CanvasManager.d.ts +39 -0
  54. package/types/Core/Container.d.ts +26 -7
  55. package/types/Core/Engine.d.ts +2 -54
  56. package/types/Core/Interfaces/IContainerPlugin.d.ts +8 -7
  57. package/types/Core/Interfaces/IDrawParticleParams.d.ts +2 -1
  58. package/types/Core/Interfaces/IParticleRetinaProps.d.ts +4 -4
  59. package/types/Core/Interfaces/IParticleUpdater.d.ts +2 -1
  60. package/types/Core/Interfaces/IShapeDrawData.d.ts +2 -1
  61. package/types/Core/Particle.d.ts +4 -4
  62. package/types/Core/{Particles.d.ts → ParticlesManager.d.ts} +4 -11
  63. package/types/Core/{Canvas.d.ts → RenderManager.d.ts} +12 -33
  64. package/types/Core/Retina.d.ts +0 -2
  65. package/types/Core/Utils/PluginManager.d.ts +62 -0
  66. package/types/Options/Classes/Options.d.ts +3 -3
  67. package/types/Options/Classes/Particles/ParticlesOptions.d.ts +3 -3
  68. package/types/Types/CanvasContextType.d.ts +1 -0
  69. package/types/Utils/CanvasUtils.d.ts +8 -5
  70. package/types/Utils/ColorUtils.d.ts +8 -8
  71. package/types/Utils/LogUtils.d.ts +1 -0
  72. package/types/Utils/OptionsUtils.d.ts +2 -2
  73. package/types/export-types.d.ts +4 -2
  74. package/umd/Core/CanvasManager.js +317 -0
  75. package/umd/Core/Container.js +61 -34
  76. package/umd/Core/Engine.js +25 -137
  77. package/umd/Core/Particle.js +29 -28
  78. package/umd/Core/{Particles.js → ParticlesManager.js} +29 -59
  79. package/umd/Core/RenderManager.js +317 -0
  80. package/umd/Core/Retina.js +3 -8
  81. package/umd/Core/Utils/PluginManager.js +159 -0
  82. package/umd/Options/Classes/Options.js +7 -7
  83. package/umd/Options/Classes/Particles/ParticlesOptions.js +5 -5
  84. package/umd/Types/CanvasContextType.js +12 -0
  85. package/umd/Utils/CanvasUtils.js +1 -1
  86. package/umd/Utils/ColorUtils.js +21 -21
  87. package/umd/Utils/LogUtils.js +1 -0
  88. package/umd/Utils/OptionsUtils.js +2 -2
  89. package/164.min.js +0 -1
  90. package/browser/Core/Canvas.js +0 -570
  91. package/cjs/Core/Canvas.js +0 -570
  92. package/esm/Core/Canvas.js +0 -570
  93. package/umd/Core/Canvas.js +0 -584
@@ -1,7 +1,7 @@
1
- import { canvasFirstIndex, canvasTag, generatedAttribute, generatedFalse, generatedTrue, loadMinIndex, loadRandomFactor, none, one, removeDeleteCount, } from "./Utils/Constants.js";
2
- import { getItemMapFromInitializer, getItemsFromInitializer, itemFromSingleOrMultiple, safeDocument, } from "../Utils/Utils.js";
1
+ import { canvasFirstIndex, canvasTag, generatedAttribute, generatedFalse, generatedTrue, loadMinIndex, loadRandomFactor, none, one, removeDeleteCount, removeMinIndex, } from "./Utils/Constants.js";
2
+ import { itemFromSingleOrMultiple, safeDocument } from "../Utils/Utils.js";
3
3
  import { EventDispatcher } from "../Utils/EventDispatcher.js";
4
- import { EventType } from "../Enums/Types/EventType.js";
4
+ import { PluginManager } from "./Utils/PluginManager.js";
5
5
  import { getLogger } from "../Utils/LogUtils.js";
6
6
  import { getRandom } from "../Utils/MathUtils.js";
7
7
  const fullPercent = "100%";
@@ -45,142 +45,41 @@ const getCanvasFromContainer = (domContainer) => {
45
45
  if (domContainer) {
46
46
  return domContainer;
47
47
  }
48
- domContainer = documentSafe.createElement("div");
48
+ domContainer = documentSafe.createElement("canvas");
49
49
  domContainer.id = id;
50
50
  domContainer.dataset[generatedAttribute] = generatedTrue;
51
51
  documentSafe.body.append(domContainer);
52
52
  return domContainer;
53
53
  };
54
54
  export class Engine {
55
- colorManagers = new Map();
56
- easingFunctions = new Map();
57
- effectDrawers = new Map();
58
- initializers = {
59
- effects: new Map(),
60
- shapes: new Map(),
61
- updaters: new Map(),
62
- };
63
- palettes = new Map();
64
- plugins = [];
65
- presets = new Map();
66
- shapeDrawers = new Map();
67
- updaters = new Map();
68
- _allLoadersSet = new Set();
69
- _configs = new Map();
55
+ pluginManager = new PluginManager(this);
70
56
  _domArray = [];
71
57
  _eventDispatcher = new EventDispatcher();
72
- _executedSet = new Set();
73
58
  _initialized = false;
74
- _isRunningLoaders = false;
75
- _loadPromises = new Set();
76
- get configs() {
77
- const res = {};
78
- for (const [name, config] of this._configs) {
79
- res[name] = config;
80
- }
81
- return res;
82
- }
83
59
  get items() {
84
60
  return this._domArray;
85
61
  }
86
62
  get version() {
87
- return "4.0.0-beta.0";
88
- }
89
- addColorManager(name, manager) {
90
- this.colorManagers.set(name, manager);
91
- }
92
- addConfig(config) {
93
- const key = config.key ?? config.name ?? "default";
94
- this._configs.set(key, config);
95
- this._eventDispatcher.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
96
- }
97
- addEasing(name, easing) {
98
- if (this.easingFunctions.get(name)) {
99
- return;
100
- }
101
- this.easingFunctions.set(name, easing);
102
- }
103
- addEffect(effect, drawer) {
104
- this.initializers.effects.set(effect, drawer);
63
+ return "4.0.0-beta.1";
105
64
  }
106
65
  addEventListener(type, listener) {
107
66
  this._eventDispatcher.addEventListener(type, listener);
108
67
  }
109
- addPalette(name, palette) {
110
- this.palettes.set(name, palette);
111
- }
112
- addParticleUpdater(name, updaterInitializer) {
113
- this.initializers.updaters.set(name, updaterInitializer);
114
- }
115
- addPlugin(plugin) {
116
- if (this.getPlugin(plugin.id)) {
117
- return;
118
- }
119
- this.plugins.push(plugin);
120
- }
121
- addPreset(preset, options, override = false) {
122
- if (!(override || !this.getPreset(preset))) {
123
- return;
124
- }
125
- this.presets.set(preset, options);
126
- }
127
- addShape(shapes, drawer) {
128
- for (const shape of shapes) {
129
- this.initializers.shapes.set(shape, drawer);
130
- }
131
- }
132
68
  checkVersion(pluginVersion) {
133
69
  if (this.version === pluginVersion) {
134
70
  return;
135
71
  }
136
72
  throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
137
73
  }
138
- clearPlugins(container) {
139
- this.effectDrawers.delete(container);
140
- this.shapeDrawers.delete(container);
141
- this.updaters.delete(container);
142
- }
143
74
  dispatchEvent(type, args) {
144
75
  this._eventDispatcher.dispatchEvent(type, args);
145
76
  }
146
- getEasing(name) {
147
- return this.easingFunctions.get(name) ?? ((value) => value);
148
- }
149
- getEffectDrawers(container, force = false) {
150
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
151
- }
152
- getPalette(name) {
153
- return this.palettes.get(name);
154
- }
155
- getPlugin(plugin) {
156
- return this.plugins.find(t => t.id === plugin);
157
- }
158
- getPreset(preset) {
159
- return this.presets.get(preset);
160
- }
161
- async getShapeDrawers(container, force = false) {
162
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
163
- }
164
- async getUpdaters(container, force = false) {
165
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
166
- }
167
77
  async init() {
168
- if (this._initialized || this._isRunningLoaders) {
78
+ if (this._initialized) {
169
79
  return;
170
80
  }
171
- this._isRunningLoaders = true;
172
- this._executedSet = new Set();
173
- this._allLoadersSet = new Set(this._loadPromises);
174
- try {
175
- for (const loader of this._allLoadersSet) {
176
- await this._runLoader(loader, this._executedSet, this._allLoadersSet);
177
- }
178
- }
179
- finally {
180
- this._loadPromises.clear();
181
- this._isRunningLoaders = false;
182
- this._initialized = true;
183
- }
81
+ await this.pluginManager.init();
82
+ this._initialized = true;
184
83
  }
185
84
  item(index) {
186
85
  const { items } = this, item = items[index];
@@ -192,7 +91,23 @@ export class Engine {
192
91
  }
193
92
  async load(params) {
194
93
  await this.init();
195
- const { Container } = await import("./Container.js"), id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options, currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container(this, id, currentOptions);
94
+ const { Container } = await import("./Container.js"), id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options, currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container({
95
+ dispatchCallback: (eventType, args) => {
96
+ this.dispatchEvent(eventType, args);
97
+ },
98
+ id,
99
+ onDestroy: (remove) => {
100
+ if (!remove) {
101
+ return;
102
+ }
103
+ const mainArr = this.items, idx = mainArr.indexOf(newItem);
104
+ if (idx >= removeMinIndex) {
105
+ mainArr.splice(idx, removeDeleteCount);
106
+ }
107
+ },
108
+ pluginManager: this.pluginManager,
109
+ sourceOptions: currentOptions,
110
+ });
196
111
  if (oldIndex >= loadMinIndex) {
197
112
  const old = this.item(oldIndex), deleteCount = old ? one : none;
198
113
  if (old && !old.destroyed) {
@@ -208,40 +123,13 @@ export class Engine {
208
123
  await newItem.start();
209
124
  return newItem;
210
125
  }
211
- loadParticlesOptions(container, options, ...sourceOptions) {
212
- const updaters = this.updaters.get(container);
213
- if (!updaters) {
214
- return;
215
- }
216
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
217
- }
218
126
  async refresh(refresh = true) {
219
127
  if (!refresh) {
220
128
  return;
221
129
  }
222
130
  await Promise.all(this.items.map(t => t.refresh()));
223
131
  }
224
- async register(...loaders) {
225
- if (this._initialized) {
226
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
227
- }
228
- for (const loader of loaders) {
229
- if (this._isRunningLoaders) {
230
- await this._runLoader(loader, this._executedSet, this._allLoadersSet);
231
- }
232
- else {
233
- this._loadPromises.add(loader);
234
- }
235
- }
236
- }
237
132
  removeEventListener(type, listener) {
238
133
  this._eventDispatcher.removeEventListener(type, listener);
239
134
  }
240
- async _runLoader(loader, executed, allLoaders) {
241
- if (executed.has(loader))
242
- return;
243
- executed.add(loader);
244
- allLoaders.add(loader);
245
- await loader(this);
246
- }
247
135
  }
@@ -33,7 +33,6 @@ function fixOutMode(data) {
33
33
  }
34
34
  }
35
35
  export class Particle {
36
- container;
37
36
  backColor;
38
37
  bubble;
39
38
  destroyed;
@@ -89,10 +88,11 @@ export class Particle {
89
88
  c: 0,
90
89
  d: 1,
91
90
  };
92
- _engine;
93
- constructor(engine, container) {
94
- this.container = container;
95
- this._engine = engine;
91
+ _container;
92
+ _pluginManager;
93
+ constructor(pluginManager, container) {
94
+ this._pluginManager = pluginManager;
95
+ this._container = container;
96
96
  }
97
97
  destroy(override) {
98
98
  if (this.unbreakable || this.destroyed) {
@@ -101,25 +101,22 @@ export class Particle {
101
101
  this.destroyed = true;
102
102
  this.bubble.inRange = false;
103
103
  this.slow.inRange = false;
104
- const container = this.container, shapeDrawer = this.shape ? container.particles.shapeDrawers.get(this.shape) : undefined;
104
+ const container = this._container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
105
105
  shapeDrawer?.particleDestroy?.(this);
106
106
  for (const plugin of container.particleDestroyedPlugins) {
107
107
  plugin.particleDestroyed?.(this, override);
108
108
  }
109
- for (const updater of container.particles.updaters) {
109
+ for (const updater of container.particleUpdaters) {
110
110
  updater.particleDestroyed?.(this, override);
111
111
  }
112
- this._engine.dispatchEvent(EventType.particleDestroyed, {
113
- container: this.container,
114
- data: {
115
- particle: this,
116
- },
112
+ this._container.dispatchEvent(EventType.particleDestroyed, {
113
+ particle: this,
117
114
  });
118
115
  }
119
116
  draw(delta) {
120
- const container = this.container, canvas = container.canvas;
121
- canvas.drawParticlePlugins(this, delta);
122
- canvas.drawParticle(this, delta);
117
+ const container = this._container, render = container.canvas.render;
118
+ render.drawParticlePlugins(this, delta);
119
+ render.drawParticle(this, delta);
123
120
  }
124
121
  getAngle() {
125
122
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
@@ -168,7 +165,7 @@ export class Particle {
168
165
  return this._cachedTransform;
169
166
  }
170
167
  init(id, position, overrideOptions, group) {
171
- const container = this.container;
168
+ const container = this._container;
172
169
  this.id = id;
173
170
  this.group = group;
174
171
  this.effectClose = true;
@@ -182,10 +179,14 @@ export class Particle {
182
179
  this.misplaced = false;
183
180
  this.retina = {
184
181
  maxDistance: {},
182
+ maxSpeed: 0,
183
+ moveDrift: 0,
184
+ moveSpeed: 0,
185
+ sizeAnimationSpeed: 0,
185
186
  };
186
187
  this.outType = ParticleOutType.normal;
187
188
  this.ignoresResizeRatio = true;
188
- const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles), reduceDuplicates = particlesOptions.reduceDuplicates, effectType = particlesOptions.effect.type, shapeType = particlesOptions.shape.type;
189
+ const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this._pluginManager, container, mainOptions.particles), reduceDuplicates = particlesOptions.reduceDuplicates, effectType = particlesOptions.effect.type, shapeType = particlesOptions.shape.type;
189
190
  this.effect = itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
190
191
  this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
191
192
  const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
@@ -206,11 +207,11 @@ export class Particle {
206
207
  }
207
208
  }
208
209
  if (this.effect === randomColorValue) {
209
- const availableEffects = [...this.container.particles.effectDrawers.keys()];
210
+ const availableEffects = [...this._container.effectDrawers.keys()];
210
211
  this.effect = availableEffects[Math.floor(getRandom() * availableEffects.length)];
211
212
  }
212
213
  if (this.shape === randomColorValue) {
213
- const availableShapes = [...this.container.particles.shapeDrawers.keys()];
214
+ const availableShapes = [...this._container.shapeDrawers.keys()];
214
215
  this.shape = availableShapes[Math.floor(getRandom() * availableShapes.length)];
215
216
  }
216
217
  this.effectData = this.effect ? loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates) : undefined;
@@ -245,13 +246,13 @@ export class Particle {
245
246
  this.sides = 24;
246
247
  let effectDrawer, shapeDrawer;
247
248
  if (this.effect) {
248
- effectDrawer = container.particles.effectDrawers.get(this.effect);
249
+ effectDrawer = container.effectDrawers.get(this.effect);
249
250
  }
250
251
  if (effectDrawer?.loadEffect) {
251
252
  effectDrawer.loadEffect(this);
252
253
  }
253
254
  if (this.shape) {
254
- shapeDrawer = container.particles.shapeDrawers.get(this.shape);
255
+ shapeDrawer = container.shapeDrawers.get(this.shape);
255
256
  }
256
257
  if (shapeDrawer?.loadShape) {
257
258
  shapeDrawer.loadShape(this);
@@ -261,7 +262,7 @@ export class Particle {
261
262
  this.sides = sideCountFunc(this);
262
263
  }
263
264
  this.spawning = false;
264
- for (const updater of particles.updaters) {
265
+ for (const updater of container.particleUpdaters) {
265
266
  updater.init(this);
266
267
  }
267
268
  effectDrawer?.particleInit?.(container, this);
@@ -271,7 +272,7 @@ export class Particle {
271
272
  }
272
273
  }
273
274
  isInsideCanvas() {
274
- const radius = this.getRadius(), canvasSize = this.container.canvas.size, position = this.position;
275
+ const radius = this.getRadius(), canvasSize = this._container.canvas.size, position = this.position;
275
276
  return (position.x >= -radius &&
276
277
  position.y >= -radius &&
277
278
  position.y <= canvasSize.height + radius &&
@@ -300,13 +301,13 @@ export class Particle {
300
301
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
301
302
  }
302
303
  reset() {
303
- for (const updater of this.container.particles.updaters) {
304
+ for (const updater of this._container.particleUpdaters) {
304
305
  updater.reset?.(this);
305
306
  }
306
307
  }
307
308
  _calcPosition = (position, zIndex) => {
308
309
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
309
- const container = this.container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size, abortController = new AbortController(), { signal } = abortController;
310
+ const container = this._container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size, abortController = new AbortController(), { signal } = abortController;
310
311
  while (!signal.aborted) {
311
312
  for (const plugin of plugins) {
312
313
  const pluginPos = plugin.particlePosition?.(posVec, this);
@@ -359,7 +360,7 @@ export class Particle {
359
360
  outMode,
360
361
  checkModes: [OutMode.bounce],
361
362
  coord: pos.x,
362
- maxCoord: this.container.canvas.size.width,
363
+ maxCoord: this._container.canvas.size.width,
363
364
  setCb: (value) => (pos.x += value),
364
365
  radius,
365
366
  });
@@ -369,7 +370,7 @@ export class Particle {
369
370
  outMode,
370
371
  checkModes: [OutMode.bounce],
371
372
  coord: pos.y,
372
- maxCoord: this.container.canvas.size.height,
373
+ maxCoord: this._container.canvas.size.height,
373
374
  setCb: (value) => (pos.y += value),
374
375
  radius,
375
376
  });
@@ -390,7 +391,7 @@ export class Particle {
390
391
  return color;
391
392
  };
392
393
  _initPosition = position => {
393
- const container = this.container, zIndexValue = getRangeValue(this.options.zIndex.value), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
394
+ const container = this._container, zIndexValue = getRangeValue(this.options.zIndex.value), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
394
395
  if (!initialPosition) {
395
396
  throw new Error("a valid position cannot be found for particle");
396
397
  }
@@ -5,15 +5,11 @@ import { Particle } from "./Particle.js";
5
5
  import { SpatialHashGrid } from "./Utils/SpatialHashGrid.js";
6
6
  import { getLogger } from "../Utils/LogUtils.js";
7
7
  import { loadParticlesOptions } from "../Utils/OptionsUtils.js";
8
- export class Particles {
8
+ export class ParticlesManager {
9
9
  checkParticlePositionPlugins;
10
- effectDrawers;
11
10
  grid;
12
- shapeDrawers;
13
- updaters;
14
11
  _array;
15
12
  _container;
16
- _engine;
17
13
  _groupLimits;
18
14
  _limit;
19
15
  _maxZIndex;
@@ -22,14 +18,15 @@ export class Particles {
22
18
  _nextId;
23
19
  _particleResetPlugins;
24
20
  _particleUpdatePlugins;
21
+ _pluginManager;
25
22
  _pool;
26
23
  _postParticleUpdatePlugins;
27
24
  _postUpdatePlugins;
28
25
  _resizeFactor;
29
26
  _updatePlugins;
30
27
  _zArray;
31
- constructor(engine, container) {
32
- this._engine = engine;
28
+ constructor(pluginManager, container) {
29
+ this._pluginManager = pluginManager;
33
30
  this._container = container;
34
31
  this._nextId = 0;
35
32
  this._array = [];
@@ -41,9 +38,6 @@ export class Particles {
41
38
  this._minZIndex = 0;
42
39
  this._maxZIndex = 0;
43
40
  this.grid = new SpatialHashGrid(spatialHashGridCellSize);
44
- this.effectDrawers = new Map();
45
- this.shapeDrawers = new Map();
46
- this.updaters = [];
47
41
  this.checkParticlePositionPlugins = [];
48
42
  this._particleResetPlugins = [];
49
43
  this._particleUpdatePlugins = [];
@@ -75,7 +69,7 @@ export class Particles {
75
69
  }
76
70
  }
77
71
  try {
78
- const particle = this._pool.pop() ?? new Particle(this._engine, this._container);
72
+ const particle = this._pool.pop() ?? new Particle(this._pluginManager, this._container);
79
73
  particle.init(this._nextId, position, overrideOptions, group);
80
74
  let canAdd = true;
81
75
  if (initializer) {
@@ -88,11 +82,8 @@ export class Particles {
88
82
  this._array.push(particle);
89
83
  this._zArray.push(particle);
90
84
  this._nextId++;
91
- this._engine.dispatchEvent(EventType.particleAdded, {
92
- container: this._container,
93
- data: {
94
- particle,
95
- },
85
+ this._container.dispatchEvent(EventType.particleAdded, {
86
+ particle,
96
87
  });
97
88
  return particle;
98
89
  }
@@ -106,19 +97,9 @@ export class Particles {
106
97
  this._zArray = [];
107
98
  }
108
99
  destroy() {
109
- const container = this._container;
110
- for (const [, effectDrawer] of this.effectDrawers) {
111
- effectDrawer.destroy?.(container);
112
- }
113
- for (const [, shapeDrawer] of this.shapeDrawers) {
114
- shapeDrawer.destroy?.(container);
115
- }
116
100
  this._array = [];
117
101
  this._pool.length = 0;
118
102
  this._zArray = [];
119
- this.effectDrawers = new Map();
120
- this.shapeDrawers = new Map();
121
- this.updaters = [];
122
103
  this.checkParticlePositionPlugins = [];
123
104
  this._particleResetPlugins = [];
124
105
  this._particleUpdatePlugins = [];
@@ -175,11 +156,11 @@ export class Particles {
175
156
  this._postParticleUpdatePlugins.push(plugin);
176
157
  }
177
158
  }
178
- await this.initPlugins();
179
- for (const drawer of this.effectDrawers.values()) {
159
+ await this._container.initDrawersAndUpdaters();
160
+ for (const drawer of this._container.effectDrawers.values()) {
180
161
  await drawer.init?.(container);
181
162
  }
182
- for (const drawer of this.shapeDrawers.values()) {
163
+ for (const drawer of this._container.shapeDrawers.values()) {
183
164
  await drawer.init?.(container);
184
165
  }
185
166
  let handled = false;
@@ -205,12 +186,6 @@ export class Particles {
205
186
  }
206
187
  }
207
188
  }
208
- async initPlugins() {
209
- const container = this._container;
210
- this.effectDrawers = await this._engine.getEffectDrawers(container, true);
211
- this.shapeDrawers = await this._engine.getShapeDrawers(container, true);
212
- this.updaters = await this._engine.getUpdaters(container, true);
213
- }
214
189
  push(nb, position, overrideOptions, group) {
215
190
  for (let i = 0; i < nb; i++) {
216
191
  this.addParticle(position, overrideOptions, group);
@@ -219,7 +194,7 @@ export class Particles {
219
194
  async redraw() {
220
195
  this.clear();
221
196
  await this.init();
222
- this._container.canvas.drawParticles({ value: 0, factor: 0 });
197
+ this._container.canvas.render.drawParticles({ value: 0, factor: 0 });
223
198
  }
224
199
  remove(particle, group, override) {
225
200
  this.removeAt(this._array.indexOf(particle), undefined, group, override);
@@ -252,7 +227,7 @@ export class Particles {
252
227
  if (!groupData) {
253
228
  continue;
254
229
  }
255
- const groupDataOptions = loadParticlesOptions(this._engine, this._container, groupData);
230
+ const groupDataOptions = loadParticlesOptions(this._pluginManager, this._container, groupData);
256
231
  this._applyDensity(groupDataOptions, pluginsCount, group);
257
232
  }
258
233
  this._applyDensity(options.particles, pluginsCount);
@@ -293,25 +268,15 @@ export class Particles {
293
268
  }
294
269
  this.grid.insert(particle);
295
270
  }
296
- if (particlesToDelete.size) {
297
- const checkDelete = (p) => !particlesToDelete.has(p);
298
- this._array = this.filter(checkDelete);
299
- this._zArray = this._zArray.filter(checkDelete);
300
- for (const particle of particlesToDelete) {
301
- this._engine.dispatchEvent(EventType.particleRemoved, {
302
- container: this._container,
303
- data: {
304
- particle,
305
- },
306
- });
307
- }
308
- this._addToPool(...particlesToDelete);
309
- }
310
271
  for (const plugin of this._postUpdatePlugins) {
311
272
  plugin.postUpdate?.(delta);
312
273
  }
313
274
  for (const particle of this._array) {
314
- for (const updater of this.updaters) {
275
+ if (particle.destroyed) {
276
+ particlesToDelete.add(particle);
277
+ continue;
278
+ }
279
+ for (const updater of this._container.particleUpdaters) {
315
280
  updater.update(particle, delta);
316
281
  }
317
282
  if (!particle.destroyed && !particle.spawning) {
@@ -319,6 +284,14 @@ export class Particles {
319
284
  plugin.postParticleUpdate?.(particle, delta);
320
285
  }
321
286
  }
287
+ else if (particle.destroyed) {
288
+ particlesToDelete.add(particle);
289
+ }
290
+ }
291
+ if (particlesToDelete.size) {
292
+ for (const particle of particlesToDelete) {
293
+ this.remove(particle);
294
+ }
322
295
  }
323
296
  delete this._resizeFactor;
324
297
  if (this._needsSort) {
@@ -381,11 +354,8 @@ export class Particles {
381
354
  this._array.splice(index, deleteCount);
382
355
  this._zArray.splice(zIdx, deleteCount);
383
356
  particle.destroy(override);
384
- this._engine.dispatchEvent(EventType.particleRemoved, {
385
- container: this._container,
386
- data: {
387
- particle,
388
- },
357
+ this._container.dispatchEvent(EventType.particleRemoved, {
358
+ particle,
389
359
  });
390
360
  this._addToPool(particle);
391
361
  return true;