@tsparticles/plugin-emitters 4.0.0-alpha.8 → 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 (101) hide show
  1. package/392.min.js +1 -0
  2. package/399.min.js +1 -0
  3. package/414.min.js +1 -0
  4. package/592.min.js +1 -0
  5. package/764.min.js +1 -0
  6. package/815.min.js +1 -0
  7. package/README.md +5 -0
  8. package/browser/EmitterInstance.js +121 -85
  9. package/browser/EmitterShapeBase.js +4 -0
  10. package/browser/EmittersInstancesManager.js +5 -3
  11. package/browser/EmittersInteractor.js +5 -1
  12. package/browser/EmittersPlugin.js +2 -1
  13. package/browser/EmittersPluginInstance.js +2 -0
  14. package/browser/Options/Classes/Emitter.js +25 -3
  15. package/browser/Options/Classes/EmitterLife.js +4 -0
  16. package/browser/Options/Classes/EmitterRate.js +2 -0
  17. package/browser/Options/Classes/EmitterShape.js +3 -0
  18. package/browser/Options/Classes/EmitterShapeReplace.js +2 -0
  19. package/browser/Options/Classes/EmitterSize.js +3 -0
  20. package/browser/Options/Classes/EmitterSpawn.js +18 -0
  21. package/browser/Options/Interfaces/IEmitterSpawn.js +1 -0
  22. package/browser/index.js +19 -9
  23. package/cjs/EmitterInstance.js +121 -85
  24. package/cjs/EmitterShapeBase.js +4 -0
  25. package/cjs/EmittersInstancesManager.js +5 -3
  26. package/cjs/EmittersInteractor.js +5 -1
  27. package/cjs/EmittersPlugin.js +2 -1
  28. package/cjs/EmittersPluginInstance.js +2 -0
  29. package/cjs/Options/Classes/Emitter.js +25 -3
  30. package/cjs/Options/Classes/EmitterLife.js +4 -0
  31. package/cjs/Options/Classes/EmitterRate.js +2 -0
  32. package/cjs/Options/Classes/EmitterShape.js +3 -0
  33. package/cjs/Options/Classes/EmitterShapeReplace.js +2 -0
  34. package/cjs/Options/Classes/EmitterSize.js +3 -0
  35. package/cjs/Options/Classes/EmitterSpawn.js +18 -0
  36. package/cjs/Options/Interfaces/IEmitterSpawn.js +1 -0
  37. package/cjs/index.js +19 -9
  38. package/dist_browser_EmitterInstance_js.js +2 -2
  39. package/dist_browser_EmittersInstancesManager_js.js +18 -8
  40. package/dist_browser_EmittersInteractor_js.js +19 -9
  41. package/dist_browser_EmittersPluginInstance_js.js +2 -2
  42. package/dist_browser_EmittersPlugin_js.js +18 -8
  43. package/dist_browser_ShapeManager_js.js +2 -2
  44. package/esm/EmitterInstance.js +121 -85
  45. package/esm/EmitterShapeBase.js +4 -0
  46. package/esm/EmittersInstancesManager.js +5 -3
  47. package/esm/EmittersInteractor.js +5 -1
  48. package/esm/EmittersPlugin.js +2 -1
  49. package/esm/EmittersPluginInstance.js +2 -0
  50. package/esm/Options/Classes/Emitter.js +25 -3
  51. package/esm/Options/Classes/EmitterLife.js +4 -0
  52. package/esm/Options/Classes/EmitterRate.js +2 -0
  53. package/esm/Options/Classes/EmitterShape.js +3 -0
  54. package/esm/Options/Classes/EmitterShapeReplace.js +2 -0
  55. package/esm/Options/Classes/EmitterSize.js +3 -0
  56. package/esm/Options/Classes/EmitterSpawn.js +18 -0
  57. package/esm/Options/Interfaces/IEmitterSpawn.js +1 -0
  58. package/esm/index.js +19 -9
  59. package/package.json +3 -3
  60. package/report.html +84 -29
  61. package/tsparticles.plugin.emitters.js +44 -32
  62. package/tsparticles.plugin.emitters.min.js +2 -2
  63. package/types/EmitterInstance.d.ts +11 -6
  64. package/types/EmittersEngine.d.ts +5 -2
  65. package/types/EmittersInstancesManager.d.ts +3 -3
  66. package/types/EmittersInteractor.d.ts +1 -0
  67. package/types/EmittersPlugin.d.ts +1 -1
  68. package/types/IEmitterShapeGenerator.d.ts +2 -2
  69. package/types/Options/Classes/Emitter.d.ts +4 -1
  70. package/types/Options/Classes/EmitterSpawn.d.ts +7 -0
  71. package/types/Options/Interfaces/IEmitter.d.ts +4 -1
  72. package/types/Options/Interfaces/IEmitterSpawn.d.ts +5 -0
  73. package/types/index.d.ts +1 -0
  74. package/umd/EmitterInstance.js +120 -84
  75. package/umd/EmitterShapeBase.js +4 -0
  76. package/umd/EmittersInstancesManager.js +5 -3
  77. package/umd/EmittersInteractor.js +5 -1
  78. package/umd/EmittersPlugin.js +2 -1
  79. package/umd/EmittersPluginInstance.js +2 -0
  80. package/umd/Options/Classes/Emitter.js +26 -4
  81. package/umd/Options/Classes/EmitterLife.js +4 -0
  82. package/umd/Options/Classes/EmitterRate.js +2 -0
  83. package/umd/Options/Classes/EmitterShape.js +3 -0
  84. package/umd/Options/Classes/EmitterShapeReplace.js +2 -0
  85. package/umd/Options/Classes/EmitterSize.js +3 -0
  86. package/umd/Options/Classes/EmitterSpawn.js +32 -0
  87. package/umd/Options/Interfaces/IEmitterSpawn.js +12 -0
  88. package/umd/index.js +20 -9
  89. package/129.min.js +0 -2
  90. package/129.min.js.LICENSE.txt +0 -1
  91. package/246.min.js +0 -2
  92. package/246.min.js.LICENSE.txt +0 -1
  93. package/330.min.js +0 -2
  94. package/330.min.js.LICENSE.txt +0 -1
  95. package/490.min.js +0 -2
  96. package/490.min.js.LICENSE.txt +0 -1
  97. package/849.min.js +0 -2
  98. package/849.min.js.LICENSE.txt +0 -1
  99. package/940.min.js +0 -2
  100. package/940.min.js.LICENSE.txt +0 -1
  101. package/tsparticles.plugin.emitters.min.js.LICENSE.txt +0 -1
package/browser/index.js CHANGED
@@ -1,18 +1,28 @@
1
1
  export async function loadEmittersPlugin(engine) {
2
- engine.checkVersion("4.0.0-alpha.8");
3
- await engine.register(async (e) => {
4
- const { loadInteractivityPlugin } = await import("@tsparticles/plugin-interactivity"), { ShapeManager } = await import("./ShapeManager.js"), { EmittersInstancesManager } = await import("./EmittersInstancesManager.js"), { EmittersPlugin } = await import("./EmittersPlugin.js"), instancesManager = new EmittersInstancesManager(e);
5
- await loadInteractivityPlugin(e);
6
- e.emitterShapeManager ??= new ShapeManager();
7
- e.addEmitterShapeGenerator ??= (name, generator) => {
8
- e.emitterShapeManager?.addShapeGenerator(name, generator);
2
+ engine.checkVersion("4.0.0-beta.1");
3
+ await engine.pluginManager.register(async (e) => {
4
+ const [{ ensureInteractivityPluginLoaded }, { ShapeManager }, { EmittersInstancesManager }, { EmittersPlugin },] = await Promise.all([
5
+ import("@tsparticles/plugin-interactivity"),
6
+ import("./ShapeManager.js"),
7
+ import("./EmittersInstancesManager.js"),
8
+ import("./EmittersPlugin.js"),
9
+ ]), pluginManager = e.pluginManager, instancesManager = new EmittersInstancesManager(pluginManager);
10
+ ensureInteractivityPluginLoaded(e);
11
+ pluginManager.emitterShapeManager ??= new ShapeManager();
12
+ pluginManager.addEmitterShapeGenerator ??= (name, generator) => {
13
+ pluginManager.emitterShapeManager?.addShapeGenerator(name, generator);
9
14
  };
10
- e.addPlugin(new EmittersPlugin(instancesManager));
11
- e.addInteractor?.("externalEmitters", async (container) => {
15
+ pluginManager.addPlugin(new EmittersPlugin(instancesManager));
16
+ pluginManager.addInteractor?.("externalEmitters", async (container) => {
12
17
  const { EmittersInteractor } = await import("./EmittersInteractor.js");
13
18
  return new EmittersInteractor(instancesManager, container);
14
19
  });
15
20
  });
16
21
  }
22
+ export function ensureEmittersPluginLoaded(e) {
23
+ if (!e.pluginManager.addEmitterShapeGenerator) {
24
+ throw new Error("tsParticles Emitters Plugin is not loaded");
25
+ }
26
+ }
17
27
  export * from "./EmitterShapeBase.js";
18
28
  export * from "./Enums/EmitterClickMode.js";
@@ -1,54 +1,55 @@
1
- import { PixelMode, Vector, calcPositionOrRandomFromSizeRanged, deepExtend, getRangeValue, getSize, hMax, half, isPointInside, itemFromSingleOrMultiple, lMax, millisecondsToSeconds, randomInRangeValue, rangeColorToHsl, sMax, safeDocument, } from "@tsparticles/engine";
1
+ import { AnimatableColor, Fill, PixelMode, Stroke, Vector, calcPositionOrRandomFromSizeRanged, deepExtend, defaultOpacity, getRangeValue, getSize, hMax, half, isPointInside, itemFromSingleOrMultiple, lMax, millisecondsToSeconds, randomInRangeValue, rangeColorToHsl, sMax, safeDocument, } from "@tsparticles/engine";
2
2
  import { Emitter } from "./Options/Classes/Emitter.js";
3
3
  import { EmitterSize } from "./Options/Classes/EmitterSize.js";
4
- const defaultLifeDelay = 0, minLifeCount = 0, defaultSpawnDelay = 0, defaultEmitDelay = 0, defaultLifeCount = -1, defaultColorAnimationFactor = 1, colorFactor = 3.6;
5
- function setParticlesOptionsColor(particlesOptions, color) {
6
- if (particlesOptions.color) {
7
- particlesOptions.color.value = color;
8
- }
9
- else {
10
- particlesOptions.color = {
11
- value: color,
12
- };
13
- }
4
+ const defaultLifeDelay = 0, minLifeCount = 0, defaultSpawnDelay = 0, defaultEmitDelay = 0, defaultLifeCount = -1, defaultColorAnimationFactor = 1, colorFactor = 3.6, defaultStrokeWidth = 1;
5
+ function setParticlesOptionsFillColor(particlesOptions, color, opacity, enable) {
6
+ particlesOptions.fill = new Fill();
7
+ particlesOptions.fill.color = AnimatableColor.create(undefined, { value: color });
8
+ particlesOptions.fill.enable = enable;
9
+ particlesOptions.fill.opacity = opacity;
10
+ }
11
+ function setParticlesOptionsStrokeColor(particlesOptions, color, opacity, width) {
12
+ particlesOptions.stroke = new Stroke();
13
+ particlesOptions.stroke.color = AnimatableColor.create(undefined, { value: color });
14
+ particlesOptions.stroke.opacity = opacity;
15
+ particlesOptions.stroke.width = width;
14
16
  }
15
17
  export class EmitterInstance {
16
- constructor(engine, container, removeCallback, options, position) {
17
- this.container = container;
18
- this.removeCallback = removeCallback;
19
- this._destroy = () => {
20
- this._mutationObserver?.disconnect();
21
- this._mutationObserver = undefined;
22
- this._resizeObserver?.disconnect();
23
- this._resizeObserver = undefined;
24
- this.removeCallback(this);
25
- this._engine.dispatchEvent("emitterDestroyed", {
26
- container: this.container,
27
- data: {
28
- emitter: this,
29
- },
30
- });
31
- };
32
- this._prepareToDie = () => {
33
- if (this._paused) {
34
- return;
35
- }
36
- const duration = this.options.life.duration !== undefined ? getRangeValue(this.options.life.duration) : undefined, minDuration = 0, minLifeCount = 0;
37
- if ((this._lifeCount > minLifeCount || this._immortal) && duration !== undefined && duration > minDuration) {
38
- this._duration = duration * millisecondsToSeconds;
39
- }
40
- };
41
- this._setColorAnimation = (animation, initValue, maxValue, factor = defaultColorAnimationFactor) => {
42
- const container = this.container;
43
- if (!animation.enable) {
44
- return initValue;
45
- }
46
- const colorOffset = randomInRangeValue(animation.offset), delay = getRangeValue(this.options.rate.delay), emitFactor = container.retina.reduceFactor
47
- ? (delay * millisecondsToSeconds) / container.retina.reduceFactor
48
- : Infinity, colorSpeed = getRangeValue(animation.speed);
49
- return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * factor) % maxValue;
50
- };
51
- this._engine = engine;
18
+ fill;
19
+ name;
20
+ options;
21
+ position;
22
+ size;
23
+ spawnFillColor;
24
+ spawnFillEnabled;
25
+ spawnFillOpacity;
26
+ spawnStrokeColor;
27
+ spawnStrokeOpacity;
28
+ spawnStrokeWidth;
29
+ _container;
30
+ _currentDuration;
31
+ _currentEmitDelay;
32
+ _currentSpawnDelay;
33
+ _duration;
34
+ _emitDelay;
35
+ _firstSpawn;
36
+ _immortal;
37
+ _initialPosition;
38
+ _lifeCount;
39
+ _mutationObserver;
40
+ _particlesOptions;
41
+ _paused;
42
+ _pluginManager;
43
+ _removeCallback;
44
+ _resizeObserver;
45
+ _shape;
46
+ _size;
47
+ _spawnDelay;
48
+ _startParticlesAdded;
49
+ constructor(pluginManager, container, removeCallback, options, position) {
50
+ this._pluginManager = pluginManager;
51
+ this._container = container;
52
+ this._removeCallback = removeCallback;
52
53
  this._currentDuration = 0;
53
54
  this._currentEmitDelay = 0;
54
55
  this._currentSpawnDelay = 0;
@@ -72,13 +73,16 @@ export class EmitterInstance {
72
73
  const particlesOptions = deepExtend({}, this.options.particles);
73
74
  particlesOptions.move ??= {};
74
75
  particlesOptions.move.direction ??= this.options.direction;
75
- if (this.options.spawnColor) {
76
- this.spawnColor = rangeColorToHsl(this._engine, this.options.spawnColor);
76
+ if (this.options.spawn.fill?.color) {
77
+ this.spawnFillColor = rangeColorToHsl(this._pluginManager, this.options.spawn.fill.color);
78
+ }
79
+ if (this.options.spawn.stroke?.color) {
80
+ this.spawnStrokeColor = rangeColorToHsl(this._pluginManager, this.options.spawn.stroke.color);
77
81
  }
78
82
  this._paused = !this.options.autoPlay;
79
83
  this._particlesOptions = particlesOptions;
80
84
  this._size = this._calcSize();
81
- this.size = getSize(this._size, this.container.canvas.size);
85
+ this.size = getSize(this._size, this._container.canvas.size);
82
86
  this._lifeCount = this.options.life.count ?? defaultLifeCount;
83
87
  this._immortal = this._lifeCount <= minLifeCount;
84
88
  if (this.options.domId) {
@@ -97,15 +101,12 @@ export class EmitterInstance {
97
101
  this._resizeObserver.observe(element);
98
102
  }
99
103
  }
100
- const shapeOptions = this.options.shape, shapeGenerator = this._engine.emitterShapeManager?.getShapeGenerator(shapeOptions.type);
104
+ const shapeOptions = this.options.shape, shapeGenerator = this._pluginManager.emitterShapeManager?.getShapeGenerator(shapeOptions.type);
101
105
  if (shapeGenerator) {
102
- this._shape = shapeGenerator.generate(this.position, this.size, this.fill, shapeOptions.options);
106
+ this._shape = shapeGenerator.generate(this._container, this.position, this.size, this.fill, shapeOptions.options);
103
107
  }
104
- this._engine.dispatchEvent("emitterCreated", {
105
- container,
106
- data: {
107
- emitter: this,
108
- },
108
+ this._container.dispatchEvent("emitterCreated", {
109
+ emitter: this,
109
110
  });
110
111
  this.play();
111
112
  }
@@ -134,7 +135,7 @@ export class EmitterInstance {
134
135
  (this._firstSpawn || this._currentSpawnDelay >= (this._spawnDelay ?? defaultSpawnDelay)))) {
135
136
  return;
136
137
  }
137
- const container = this.container;
138
+ const container = this._container;
138
139
  if (this._emitDelay === undefined) {
139
140
  const delay = getRangeValue(this.options.rate.delay);
140
141
  this._emitDelay = container.retina.reduceFactor
@@ -146,7 +147,7 @@ export class EmitterInstance {
146
147
  }
147
148
  }
148
149
  resize() {
149
- const initialPosition = this._initialPosition, container = this.container;
150
+ const initialPosition = this._initialPosition, container = this._container;
150
151
  this.position =
151
152
  initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
152
153
  ? initialPosition
@@ -159,7 +160,7 @@ export class EmitterInstance {
159
160
  if (this._paused) {
160
161
  return;
161
162
  }
162
- const container = this.container;
163
+ const container = this._container;
163
164
  if (this._firstSpawn) {
164
165
  this._firstSpawn = false;
165
166
  this._currentSpawnDelay = this._spawnDelay ?? defaultSpawnDelay;
@@ -197,11 +198,9 @@ export class EmitterInstance {
197
198
  if (this._spawnDelay !== undefined) {
198
199
  this._currentSpawnDelay += delta.value;
199
200
  if (this._currentSpawnDelay >= this._spawnDelay) {
200
- this._engine.dispatchEvent("emitterPlay", {
201
- container: this.container,
202
- });
201
+ this._container.dispatchEvent("emitterPlay");
203
202
  this.play();
204
- this._currentSpawnDelay -= this._currentSpawnDelay;
203
+ this._currentSpawnDelay -= this._spawnDelay;
205
204
  delete this._spawnDelay;
206
205
  }
207
206
  }
@@ -214,7 +213,7 @@ export class EmitterInstance {
214
213
  }
215
214
  }
216
215
  _calcPosition() {
217
- const container = this.container;
216
+ const container = this._container;
218
217
  if (this.options.domId) {
219
218
  const element = safeDocument().getElementById(this.options.domId);
220
219
  if (element) {
@@ -231,7 +230,7 @@ export class EmitterInstance {
231
230
  });
232
231
  }
233
232
  _calcSize() {
234
- const container = this.container;
233
+ const container = this._container;
235
234
  if (this.options.domId) {
236
235
  const element = safeDocument().getElementById(this.options.domId);
237
236
  if (element) {
@@ -254,6 +253,16 @@ export class EmitterInstance {
254
253
  return size;
255
254
  })());
256
255
  }
256
+ _destroy = () => {
257
+ this._mutationObserver?.disconnect();
258
+ this._mutationObserver = undefined;
259
+ this._resizeObserver?.disconnect();
260
+ this._resizeObserver = undefined;
261
+ this._removeCallback(this);
262
+ this._container.dispatchEvent("emitterDestroyed", {
263
+ emitter: this,
264
+ });
265
+ };
257
266
  _emit() {
258
267
  if (this._paused) {
259
268
  return;
@@ -263,18 +272,36 @@ export class EmitterInstance {
263
272
  }
264
273
  _emitParticles(quantity) {
265
274
  const singleParticlesOptions = (itemFromSingleOrMultiple(this._particlesOptions) ??
266
- {}), hslAnimation = this.options.spawnColor?.animation, reduceFactor = this.container.retina.reduceFactor, needsColorAnimation = !!hslAnimation, needsShapeData = !!this._shape, needsCopy = needsColorAnimation || needsShapeData, maxValues = needsColorAnimation ? { h: hMax, s: sMax, l: lMax } : null, shapeOptions = this.options.shape;
275
+ {}), fillHslAnimation = this.options.spawn.fill?.color.animation, fillEnabled = this.options.spawn.fill?.enable ?? !!this.options.spawn.fill?.color, fillOpacity = this.options.spawn.fill?.opacity === undefined
276
+ ? defaultOpacity
277
+ : getRangeValue(this.options.spawn.fill.opacity), strokeHslAnimation = this.options.spawn.stroke?.color?.animation, strokeOpacity = this.options.spawn.stroke?.opacity === undefined
278
+ ? defaultOpacity
279
+ : getRangeValue(this.options.spawn.stroke.opacity), strokeWidth = this.options.spawn.stroke?.width === undefined
280
+ ? defaultStrokeWidth
281
+ : getRangeValue(this.options.spawn.stroke.width), reduceFactor = this._container.retina.reduceFactor, needsFillColorAnimation = !!fillHslAnimation, needsStrokeColorAnimation = !!strokeHslAnimation, needsShapeData = !!this._shape, needsColorAnimation = needsFillColorAnimation || needsStrokeColorAnimation, needsCopy = needsColorAnimation || needsShapeData, maxValues = needsColorAnimation ? { h: hMax, s: sMax, l: lMax } : null, shapeOptions = this.options.shape;
267
282
  for (let i = 0; i < quantity * reduceFactor; i++) {
268
283
  const particlesOptions = needsCopy
269
284
  ? deepExtend({}, singleParticlesOptions)
270
285
  : singleParticlesOptions;
271
- if (this.spawnColor) {
272
- if (hslAnimation && maxValues) {
273
- this.spawnColor.h = this._setColorAnimation(hslAnimation.h, this.spawnColor.h, maxValues.h, colorFactor);
274
- this.spawnColor.s = this._setColorAnimation(hslAnimation.s, this.spawnColor.s, maxValues.s);
275
- this.spawnColor.l = this._setColorAnimation(hslAnimation.l, this.spawnColor.l, maxValues.l);
286
+ this.spawnFillOpacity = fillOpacity;
287
+ this.spawnFillEnabled = fillEnabled;
288
+ this.spawnStrokeOpacity = strokeOpacity;
289
+ this.spawnStrokeWidth = strokeWidth;
290
+ if (this.spawnFillColor) {
291
+ if (fillHslAnimation && maxValues) {
292
+ this.spawnFillColor.h = this._setColorAnimation(fillHslAnimation.h, this.spawnFillColor.h, maxValues.h, colorFactor);
293
+ this.spawnFillColor.s = this._setColorAnimation(fillHslAnimation.s, this.spawnFillColor.s, maxValues.s);
294
+ this.spawnFillColor.l = this._setColorAnimation(fillHslAnimation.l, this.spawnFillColor.l, maxValues.l);
295
+ }
296
+ setParticlesOptionsFillColor(particlesOptions, this.spawnFillColor, this.spawnFillOpacity, this.spawnFillEnabled);
297
+ }
298
+ if (this.spawnStrokeColor) {
299
+ if (strokeHslAnimation && maxValues) {
300
+ this.spawnStrokeColor.h = this._setColorAnimation(strokeHslAnimation.h, this.spawnStrokeColor.h, maxValues.h, colorFactor);
301
+ this.spawnStrokeColor.s = this._setColorAnimation(strokeHslAnimation.s, this.spawnStrokeColor.s, maxValues.s);
302
+ this.spawnStrokeColor.l = this._setColorAnimation(strokeHslAnimation.l, this.spawnStrokeColor.l, maxValues.l);
276
303
  }
277
- setParticlesOptionsColor(particlesOptions, this.spawnColor);
304
+ setParticlesOptionsStrokeColor(particlesOptions, this.spawnStrokeColor, this.spawnStrokeOpacity, this.spawnStrokeWidth);
278
305
  }
279
306
  let position = this.position;
280
307
  if (this._shape) {
@@ -283,17 +310,7 @@ export class EmitterInstance {
283
310
  position = shapePosData.position;
284
311
  const replaceData = shapeOptions.replace;
285
312
  if (replaceData.color && shapePosData.color) {
286
- setParticlesOptionsColor(particlesOptions, shapePosData.color);
287
- }
288
- if (replaceData.opacity) {
289
- if (particlesOptions.opacity) {
290
- particlesOptions.opacity.value = shapePosData.opacity;
291
- }
292
- else {
293
- particlesOptions.opacity = {
294
- value: shapePosData.opacity,
295
- };
296
- }
313
+ setParticlesOptionsFillColor(particlesOptions, shapePosData.color, replaceData.opacity ? (shapePosData.opacity ?? defaultOpacity) : defaultOpacity, true);
297
314
  }
298
315
  }
299
316
  else {
@@ -301,8 +318,27 @@ export class EmitterInstance {
301
318
  }
302
319
  }
303
320
  if (position) {
304
- this.container.particles.addParticle(position, particlesOptions);
321
+ this._container.particles.addParticle(position, particlesOptions);
305
322
  }
306
323
  }
307
324
  }
325
+ _prepareToDie = () => {
326
+ if (this._paused) {
327
+ return;
328
+ }
329
+ const duration = this.options.life.duration !== undefined ? getRangeValue(this.options.life.duration) : undefined, minDuration = 0, minLifeCount = 0;
330
+ if ((this._lifeCount > minLifeCount || this._immortal) && duration !== undefined && duration > minDuration) {
331
+ this._duration = duration * millisecondsToSeconds;
332
+ }
333
+ };
334
+ _setColorAnimation = (animation, initValue, maxValue, factor = defaultColorAnimationFactor) => {
335
+ const container = this._container;
336
+ if (!animation.enable) {
337
+ return initValue;
338
+ }
339
+ const colorOffset = randomInRangeValue(animation.offset), delay = getRangeValue(this.options.rate.delay), emitFactor = container.retina.reduceFactor
340
+ ? (delay * millisecondsToSeconds) / container.retina.reduceFactor
341
+ : Infinity, colorSpeed = getRangeValue(animation.speed);
342
+ return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * factor) % maxValue;
343
+ };
308
344
  }
@@ -1,4 +1,8 @@
1
1
  export class EmitterShapeBase {
2
+ fill;
3
+ options;
4
+ position;
5
+ size;
2
6
  constructor(position, size, fill, options) {
3
7
  this.position = position;
4
8
  this.size = size;
@@ -2,14 +2,16 @@ import { isNumber } from "@tsparticles/engine";
2
2
  import { Emitter } from "./Options/Classes/Emitter.js";
3
3
  const defaultIndex = 0;
4
4
  export class EmittersInstancesManager {
5
- constructor(engine) {
5
+ _containerArrays;
6
+ _pluginManager;
7
+ constructor(pluginManager) {
6
8
  this._containerArrays = new Map();
7
- this._engine = engine;
9
+ this._pluginManager = pluginManager;
8
10
  }
9
11
  async addEmitter(container, options, position) {
10
12
  const emitterOptions = new Emitter();
11
13
  emitterOptions.load(options);
12
- const { EmitterInstance } = await import("./EmitterInstance.js"), emitter = new EmitterInstance(this._engine, container, (emitter) => {
14
+ const { EmitterInstance } = await import("./EmitterInstance.js"), emitter = new EmitterInstance(this._pluginManager, container, (emitter) => {
13
15
  this.removeEmitter(container, emitter);
14
16
  }, emitterOptions, position);
15
17
  await emitter.init();
@@ -4,9 +4,13 @@ import { Emitter } from "./Options/Classes/Emitter.js";
4
4
  import { defaultRandomOptions } from "./constants.js";
5
5
  const emittersMode = "emitters";
6
6
  export class EmittersInteractor extends ExternalInteractorBase {
7
+ handleClickMode;
8
+ maxDistance;
9
+ _instancesManager;
7
10
  constructor(instancesManager, container) {
8
11
  super(container);
9
12
  this._instancesManager = instancesManager;
13
+ this.maxDistance = 0;
10
14
  this.handleClickMode = (mode, interactivityData) => {
11
15
  const container = this.container, options = container.actualOptions, modeEmitters = options.interactivity.modes.emitters;
12
16
  if (!modeEmitters || mode !== emittersMode) {
@@ -77,7 +81,7 @@ export class EmittersInteractor extends ExternalInteractorBase {
77
81
  options.emitters.value.push(tmp);
78
82
  }
79
83
  }
80
- else if (Object.hasOwn(source.emitters, "value")) {
84
+ else if ("value" in source.emitters) {
81
85
  const emitterModeOptions = source.emitters;
82
86
  options.emitters.random.enable = emitterModeOptions.random?.enable ?? options.emitters.random.enable;
83
87
  options.emitters.random.count = emitterModeOptions.random?.count ?? options.emitters.random.count;
@@ -1,9 +1,10 @@
1
1
  import { executeOnSingleOrMultiple, isArray, } from "@tsparticles/engine";
2
2
  import { Emitter } from "./Options/Classes/Emitter.js";
3
3
  export class EmittersPlugin {
4
+ id = "emitters";
5
+ _instancesManager;
4
6
  constructor(instancesManager) {
5
7
  this._instancesManager = instancesManager;
6
- this.id = "emitters";
7
8
  }
8
9
  async getPlugin(container) {
9
10
  const { EmittersPluginInstance } = await import("./EmittersPluginInstance.js");
@@ -1,5 +1,7 @@
1
1
  import { isArray } from "@tsparticles/engine";
2
2
  export class EmittersPluginInstance {
3
+ container;
4
+ _instancesManager;
3
5
  constructor(instancesManager, container) {
4
6
  this.container = container;
5
7
  this._instancesManager = instancesManager;
@@ -3,13 +3,30 @@ import { EmitterLife } from "./EmitterLife.js";
3
3
  import { EmitterRate } from "./EmitterRate.js";
4
4
  import { EmitterShape } from "./EmitterShape.js";
5
5
  import { EmitterSize } from "./EmitterSize.js";
6
+ import { EmitterSpawn } from "./EmitterSpawn.js";
6
7
  export class Emitter {
8
+ autoPlay;
9
+ direction;
10
+ domId;
11
+ fill;
12
+ life;
13
+ name;
14
+ particles;
15
+ position;
16
+ rate;
17
+ shape;
18
+ size;
19
+ spawn;
20
+ spawnFillColor;
21
+ spawnStrokeColor;
22
+ startCount;
7
23
  constructor() {
8
24
  this.autoPlay = true;
9
25
  this.fill = true;
10
26
  this.life = new EmitterLife();
11
27
  this.rate = new EmitterRate();
12
28
  this.shape = new EmitterShape();
29
+ this.spawn = new EmitterSpawn();
13
30
  this.startCount = 0;
14
31
  }
15
32
  load(data) {
@@ -37,6 +54,7 @@ export class Emitter {
37
54
  });
38
55
  this.rate.load(data.rate);
39
56
  this.shape.load(data.shape);
57
+ this.spawn.load(data.spawn);
40
58
  if (data.position !== undefined) {
41
59
  this.position = {};
42
60
  if (data.position.x !== undefined) {
@@ -46,9 +64,13 @@ export class Emitter {
46
64
  this.position.y = setRangeValue(data.position.y);
47
65
  }
48
66
  }
49
- if (data.spawnColor !== undefined) {
50
- this.spawnColor ??= new AnimatableColor();
51
- this.spawnColor.load(data.spawnColor);
67
+ if (data.spawnFillColor !== undefined) {
68
+ this.spawnFillColor ??= new AnimatableColor();
69
+ this.spawnFillColor.load(data.spawnFillColor);
70
+ }
71
+ if (data.spawnStrokeColor !== undefined) {
72
+ this.spawnStrokeColor ??= new AnimatableColor();
73
+ this.spawnStrokeColor.load(data.spawnStrokeColor);
52
74
  }
53
75
  if (data.startCount !== undefined) {
54
76
  this.startCount = data.startCount;
@@ -1,5 +1,9 @@
1
1
  import { isNull, setRangeValue } from "@tsparticles/engine";
2
2
  export class EmitterLife {
3
+ count;
4
+ delay;
5
+ duration;
6
+ wait;
3
7
  constructor() {
4
8
  this.wait = false;
5
9
  }
@@ -1,5 +1,7 @@
1
1
  import { isNull, setRangeValue } from "@tsparticles/engine";
2
2
  export class EmitterRate {
3
+ delay;
4
+ quantity;
3
5
  constructor() {
4
6
  this.quantity = 1;
5
7
  this.delay = 0.1;
@@ -1,6 +1,9 @@
1
1
  import { deepExtend, isNull } from "@tsparticles/engine";
2
2
  import { EmitterShapeReplace } from "./EmitterShapeReplace.js";
3
3
  export class EmitterShape {
4
+ options;
5
+ replace;
6
+ type;
4
7
  constructor() {
5
8
  this.options = {};
6
9
  this.replace = new EmitterShapeReplace();
@@ -1,5 +1,7 @@
1
1
  import { isNull } from "@tsparticles/engine";
2
2
  export class EmitterShapeReplace {
3
+ color;
4
+ opacity;
3
5
  constructor() {
4
6
  this.color = false;
5
7
  this.opacity = false;
@@ -1,5 +1,8 @@
1
1
  import { PixelMode, isNull } from "@tsparticles/engine";
2
2
  export class EmitterSize {
3
+ height;
4
+ mode;
5
+ width;
3
6
  constructor() {
4
7
  this.mode = PixelMode.percent;
5
8
  this.height = 0;
@@ -0,0 +1,18 @@
1
+ import { Fill, Stroke, isNull } from "@tsparticles/engine";
2
+ export class EmitterSpawn {
3
+ fill;
4
+ stroke;
5
+ load(data) {
6
+ if (isNull(data)) {
7
+ return;
8
+ }
9
+ if (data.fill) {
10
+ this.fill ??= new Fill();
11
+ this.fill.load(data.fill);
12
+ }
13
+ if (data.stroke) {
14
+ this.stroke ??= new Stroke();
15
+ this.stroke.load(data.stroke);
16
+ }
17
+ }
18
+ }
@@ -0,0 +1 @@
1
+ export {};
package/cjs/index.js CHANGED
@@ -1,18 +1,28 @@
1
1
  export async function loadEmittersPlugin(engine) {
2
- engine.checkVersion("4.0.0-alpha.8");
3
- await engine.register(async (e) => {
4
- const { loadInteractivityPlugin } = await import("@tsparticles/plugin-interactivity"), { ShapeManager } = await import("./ShapeManager.js"), { EmittersInstancesManager } = await import("./EmittersInstancesManager.js"), { EmittersPlugin } = await import("./EmittersPlugin.js"), instancesManager = new EmittersInstancesManager(e);
5
- await loadInteractivityPlugin(e);
6
- e.emitterShapeManager ??= new ShapeManager();
7
- e.addEmitterShapeGenerator ??= (name, generator) => {
8
- e.emitterShapeManager?.addShapeGenerator(name, generator);
2
+ engine.checkVersion("4.0.0-beta.1");
3
+ await engine.pluginManager.register(async (e) => {
4
+ const [{ ensureInteractivityPluginLoaded }, { ShapeManager }, { EmittersInstancesManager }, { EmittersPlugin },] = await Promise.all([
5
+ import("@tsparticles/plugin-interactivity"),
6
+ import("./ShapeManager.js"),
7
+ import("./EmittersInstancesManager.js"),
8
+ import("./EmittersPlugin.js"),
9
+ ]), pluginManager = e.pluginManager, instancesManager = new EmittersInstancesManager(pluginManager);
10
+ ensureInteractivityPluginLoaded(e);
11
+ pluginManager.emitterShapeManager ??= new ShapeManager();
12
+ pluginManager.addEmitterShapeGenerator ??= (name, generator) => {
13
+ pluginManager.emitterShapeManager?.addShapeGenerator(name, generator);
9
14
  };
10
- e.addPlugin(new EmittersPlugin(instancesManager));
11
- e.addInteractor?.("externalEmitters", async (container) => {
15
+ pluginManager.addPlugin(new EmittersPlugin(instancesManager));
16
+ pluginManager.addInteractor?.("externalEmitters", async (container) => {
12
17
  const { EmittersInteractor } = await import("./EmittersInteractor.js");
13
18
  return new EmittersInteractor(instancesManager, container);
14
19
  });
15
20
  });
16
21
  }
22
+ export function ensureEmittersPluginLoaded(e) {
23
+ if (!e.pluginManager.addEmitterShapeGenerator) {
24
+ throw new Error("tsParticles Emitters Plugin is not loaded");
25
+ }
26
+ }
17
27
  export * from "./EmitterShapeBase.js";
18
28
  export * from "./Enums/EmitterClickMode.js";