@tsparticles/plugin-emitters 4.0.0-alpha.2 → 4.0.0-alpha.21

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 (98) hide show
  1. package/278.min.js +1 -0
  2. package/615.min.js +1 -0
  3. package/751.min.js +1 -0
  4. package/816.min.js +1 -0
  5. package/88.min.js +1 -0
  6. package/975.min.js +1 -0
  7. package/README.md +5 -0
  8. package/browser/EmitterInstance.js +69 -47
  9. package/browser/EmitterShapeBase.js +4 -0
  10. package/browser/EmittersInstancesManager.js +71 -0
  11. package/browser/EmittersInteractor.js +114 -0
  12. package/browser/EmittersPlugin.js +10 -56
  13. package/browser/EmittersPluginInstance.js +44 -0
  14. package/browser/Options/Classes/Emitter.js +13 -0
  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/ShapeManager.js +4 -4
  21. package/browser/constants.js +4 -0
  22. package/browser/index.js +20 -6
  23. package/cjs/EmitterInstance.js +69 -47
  24. package/cjs/EmitterShapeBase.js +4 -0
  25. package/cjs/EmittersInstancesManager.js +71 -0
  26. package/cjs/EmittersInteractor.js +114 -0
  27. package/cjs/EmittersPlugin.js +10 -56
  28. package/cjs/EmittersPluginInstance.js +44 -0
  29. package/cjs/Options/Classes/Emitter.js +13 -0
  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/ShapeManager.js +4 -4
  36. package/cjs/constants.js +4 -0
  37. package/cjs/index.js +20 -6
  38. package/dist_browser_EmitterInstance_js.js +30 -0
  39. package/dist_browser_EmittersInstancesManager_js.js +90 -0
  40. package/dist_browser_EmittersInteractor_js.js +100 -0
  41. package/dist_browser_EmittersPluginInstance_js.js +30 -0
  42. package/dist_browser_EmittersPlugin_js.js +8 -28
  43. package/dist_browser_ShapeManager_js.js +2 -2
  44. package/esm/EmitterInstance.js +69 -47
  45. package/esm/EmitterShapeBase.js +4 -0
  46. package/esm/EmittersInstancesManager.js +71 -0
  47. package/esm/EmittersInteractor.js +114 -0
  48. package/esm/EmittersPlugin.js +10 -56
  49. package/esm/EmittersPluginInstance.js +44 -0
  50. package/esm/Options/Classes/Emitter.js +13 -0
  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/ShapeManager.js +4 -4
  57. package/esm/constants.js +4 -0
  58. package/esm/index.js +20 -6
  59. package/package.json +3 -2
  60. package/report.html +3 -3
  61. package/tsparticles.plugin.emitters.js +58 -18
  62. package/tsparticles.plugin.emitters.min.js +2 -2
  63. package/types/EmitterContainer.d.ts +8 -7
  64. package/types/EmitterInstance.d.ts +2 -3
  65. package/types/EmittersEngine.d.ts +2 -2
  66. package/types/EmittersInstancesManager.d.ts +15 -0
  67. package/types/EmittersInteractor.d.ts +18 -0
  68. package/types/EmittersPlugin.d.ts +7 -8
  69. package/types/EmittersPluginInstance.d.ts +14 -0
  70. package/types/IEmitterShapeGenerator.d.ts +2 -2
  71. package/types/constants.d.ts +2 -0
  72. package/types/index.d.ts +3 -2
  73. package/types/types.d.ts +15 -9
  74. package/umd/EmitterInstance.js +69 -47
  75. package/umd/EmitterShapeBase.js +4 -0
  76. package/umd/EmittersInstancesManager.js +119 -0
  77. package/umd/EmittersInteractor.js +128 -0
  78. package/umd/EmittersPlugin.js +44 -56
  79. package/umd/EmittersPluginInstance.js +58 -0
  80. package/umd/Options/Classes/Emitter.js +13 -0
  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/ShapeManager.js +4 -4
  87. package/umd/constants.js +17 -0
  88. package/umd/index.js +21 -6
  89. package/214.min.js +0 -2
  90. package/214.min.js.LICENSE.txt +0 -1
  91. package/921.min.js +0 -2
  92. package/921.min.js.LICENSE.txt +0 -1
  93. package/browser/Emitters.js +0 -128
  94. package/cjs/Emitters.js +0 -128
  95. package/esm/Emitters.js +0 -128
  96. package/tsparticles.plugin.emitters.min.js.LICENSE.txt +0 -1
  97. package/types/Emitters.d.ts +0 -24
  98. package/umd/Emitters.js +0 -142
@@ -1,7 +1,7 @@
1
1
  import { PixelMode, Vector, calcPositionOrRandomFromSizeRanged, deepExtend, 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;
4
+ const defaultLifeDelay = 0, minLifeCount = 0, defaultSpawnDelay = 0, defaultEmitDelay = 0, defaultLifeCount = -1, defaultColorAnimationFactor = 1, colorFactor = 3.6;
5
5
  function setParticlesOptionsColor(particlesOptions, color) {
6
6
  if (particlesOptions.color) {
7
7
  particlesOptions.color.value = color;
@@ -13,41 +13,35 @@ function setParticlesOptionsColor(particlesOptions, color) {
13
13
  }
14
14
  }
15
15
  export class EmitterInstance {
16
- constructor(engine, emitters, container, options, position) {
17
- this.emitters = emitters;
16
+ container;
17
+ removeCallback;
18
+ fill;
19
+ name;
20
+ options;
21
+ position;
22
+ size;
23
+ spawnColor;
24
+ _currentDuration;
25
+ _currentEmitDelay;
26
+ _currentSpawnDelay;
27
+ _duration;
28
+ _emitDelay;
29
+ _engine;
30
+ _firstSpawn;
31
+ _immortal;
32
+ _initialPosition;
33
+ _lifeCount;
34
+ _mutationObserver;
35
+ _particlesOptions;
36
+ _paused;
37
+ _resizeObserver;
38
+ _shape;
39
+ _size;
40
+ _spawnDelay;
41
+ _startParticlesAdded;
42
+ constructor(engine, container, removeCallback, options, position) {
18
43
  this.container = container;
19
- this._destroy = () => {
20
- this._mutationObserver?.disconnect();
21
- this._mutationObserver = undefined;
22
- this._resizeObserver?.disconnect();
23
- this._resizeObserver = undefined;
24
- this.emitters.removeEmitter(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
- };
44
+ this.removeCallback = removeCallback;
51
45
  this._engine = engine;
52
46
  this._currentDuration = 0;
53
47
  this._currentEmitDelay = 0;
@@ -99,7 +93,7 @@ export class EmitterInstance {
99
93
  }
100
94
  const shapeOptions = this.options.shape, shapeGenerator = this._engine.emitterShapeManager?.getShapeGenerator(shapeOptions.type);
101
95
  if (shapeGenerator) {
102
- this._shape = shapeGenerator.generate(this.position, this.size, this.fill, shapeOptions.options);
96
+ this._shape = shapeGenerator.generate(this.container, this.position, this.size, this.fill, shapeOptions.options);
103
97
  }
104
98
  this._engine.dispatchEvent("emitterCreated", {
105
99
  container,
@@ -201,7 +195,7 @@ export class EmitterInstance {
201
195
  container: this.container,
202
196
  });
203
197
  this.play();
204
- this._currentSpawnDelay -= this._currentSpawnDelay;
198
+ this._currentSpawnDelay -= this._spawnDelay;
205
199
  delete this._spawnDelay;
206
200
  }
207
201
  }
@@ -254,6 +248,19 @@ export class EmitterInstance {
254
248
  return size;
255
249
  })());
256
250
  }
251
+ _destroy = () => {
252
+ this._mutationObserver?.disconnect();
253
+ this._mutationObserver = undefined;
254
+ this._resizeObserver?.disconnect();
255
+ this._resizeObserver = undefined;
256
+ this.removeCallback(this);
257
+ this._engine.dispatchEvent("emitterDestroyed", {
258
+ container: this.container,
259
+ data: {
260
+ emitter: this,
261
+ },
262
+ });
263
+ };
257
264
  _emit() {
258
265
  if (this._paused) {
259
266
  return;
@@ -262,24 +269,20 @@ export class EmitterInstance {
262
269
  this._emitParticles(quantity);
263
270
  }
264
271
  _emitParticles(quantity) {
265
- const singleParticlesOptions = itemFromSingleOrMultiple(this._particlesOptions), reduceFactor = this.container.retina.reduceFactor;
272
+ const singleParticlesOptions = (itemFromSingleOrMultiple(this._particlesOptions) ??
273
+ {}), 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;
266
274
  for (let i = 0; i < quantity * reduceFactor; i++) {
267
- const particlesOptions = deepExtend({}, singleParticlesOptions);
275
+ const particlesOptions = needsCopy
276
+ ? deepExtend({}, singleParticlesOptions)
277
+ : singleParticlesOptions;
268
278
  if (this.spawnColor) {
269
- const hslAnimation = this.options.spawnColor?.animation;
270
- if (hslAnimation) {
271
- const maxValues = {
272
- h: hMax,
273
- s: sMax,
274
- l: lMax,
275
- }, colorFactor = 3.6;
279
+ if (hslAnimation && maxValues) {
276
280
  this.spawnColor.h = this._setColorAnimation(hslAnimation.h, this.spawnColor.h, maxValues.h, colorFactor);
277
281
  this.spawnColor.s = this._setColorAnimation(hslAnimation.s, this.spawnColor.s, maxValues.s);
278
282
  this.spawnColor.l = this._setColorAnimation(hslAnimation.l, this.spawnColor.l, maxValues.l);
279
283
  }
280
284
  setParticlesOptionsColor(particlesOptions, this.spawnColor);
281
285
  }
282
- const shapeOptions = this.options.shape;
283
286
  let position = this.position;
284
287
  if (this._shape) {
285
288
  const shapePosData = this._shape.randomPosition();
@@ -309,4 +312,23 @@ export class EmitterInstance {
309
312
  }
310
313
  }
311
314
  }
315
+ _prepareToDie = () => {
316
+ if (this._paused) {
317
+ return;
318
+ }
319
+ const duration = this.options.life.duration !== undefined ? getRangeValue(this.options.life.duration) : undefined, minDuration = 0, minLifeCount = 0;
320
+ if ((this._lifeCount > minLifeCount || this._immortal) && duration !== undefined && duration > minDuration) {
321
+ this._duration = duration * millisecondsToSeconds;
322
+ }
323
+ };
324
+ _setColorAnimation = (animation, initValue, maxValue, factor = defaultColorAnimationFactor) => {
325
+ const container = this.container;
326
+ if (!animation.enable) {
327
+ return initValue;
328
+ }
329
+ const colorOffset = randomInRangeValue(animation.offset), delay = getRangeValue(this.options.rate.delay), emitFactor = container.retina.reduceFactor
330
+ ? (delay * millisecondsToSeconds) / container.retina.reduceFactor
331
+ : Infinity, colorSpeed = getRangeValue(animation.speed);
332
+ return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * factor) % maxValue;
333
+ };
312
334
  }
@@ -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;
@@ -0,0 +1,71 @@
1
+ import { isNumber } from "@tsparticles/engine";
2
+ import { Emitter } from "./Options/Classes/Emitter.js";
3
+ const defaultIndex = 0;
4
+ export class EmittersInstancesManager {
5
+ _containerArrays;
6
+ _engine;
7
+ constructor(engine) {
8
+ this._containerArrays = new Map();
9
+ this._engine = engine;
10
+ }
11
+ async addEmitter(container, options, position) {
12
+ const emitterOptions = new Emitter();
13
+ emitterOptions.load(options);
14
+ const { EmitterInstance } = await import("./EmitterInstance.js"), emitter = new EmitterInstance(this._engine, container, (emitter) => {
15
+ this.removeEmitter(container, emitter);
16
+ }, emitterOptions, position);
17
+ await emitter.init();
18
+ this.getArray(container).push(emitter);
19
+ return emitter;
20
+ }
21
+ clear(container) {
22
+ this.initContainer(container);
23
+ this._containerArrays.set(container, []);
24
+ }
25
+ getArray(container) {
26
+ this.initContainer(container);
27
+ let array = this._containerArrays.get(container);
28
+ if (!array) {
29
+ array = [];
30
+ this._containerArrays.set(container, array);
31
+ }
32
+ return array;
33
+ }
34
+ initContainer(container) {
35
+ if (this._containerArrays.has(container)) {
36
+ return;
37
+ }
38
+ this._containerArrays.set(container, []);
39
+ container.getEmitter = (idxOrName) => {
40
+ const array = this.getArray(container);
41
+ return idxOrName === undefined || isNumber(idxOrName)
42
+ ? array[idxOrName ?? defaultIndex]
43
+ : array.find(t => t.name === idxOrName);
44
+ };
45
+ container.addEmitter = async (options, position) => this.addEmitter(container, options, position);
46
+ container.removeEmitter = (idxOrName) => {
47
+ const emitter = container.getEmitter?.(idxOrName);
48
+ if (emitter) {
49
+ this.removeEmitter(container, emitter);
50
+ }
51
+ };
52
+ container.playEmitter = (idxOrName) => {
53
+ const emitter = container.getEmitter?.(idxOrName);
54
+ if (emitter) {
55
+ emitter.externalPlay();
56
+ }
57
+ };
58
+ container.pauseEmitter = (idxOrName) => {
59
+ const emitter = container.getEmitter?.(idxOrName);
60
+ if (emitter) {
61
+ emitter.externalPause();
62
+ }
63
+ };
64
+ }
65
+ removeEmitter(container, emitter) {
66
+ const index = this.getArray(container).indexOf(emitter), minIndex = 0, deleteCount = 1;
67
+ if (index >= minIndex) {
68
+ this.getArray(container).splice(index, deleteCount);
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,114 @@
1
+ import { ExternalInteractorBase, } from "@tsparticles/plugin-interactivity";
2
+ import { arrayRandomIndex, executeOnSingleOrMultiple, isArray, isInArray, itemFromArray, } from "@tsparticles/engine";
3
+ import { Emitter } from "./Options/Classes/Emitter.js";
4
+ import { defaultRandomOptions } from "./constants.js";
5
+ const emittersMode = "emitters";
6
+ export class EmittersInteractor extends ExternalInteractorBase {
7
+ handleClickMode;
8
+ _instancesManager;
9
+ constructor(instancesManager, container) {
10
+ super(container);
11
+ this._instancesManager = instancesManager;
12
+ this.handleClickMode = (mode, interactivityData) => {
13
+ const container = this.container, options = container.actualOptions, modeEmitters = options.interactivity.modes.emitters;
14
+ if (!modeEmitters || mode !== emittersMode) {
15
+ return;
16
+ }
17
+ let emittersModeOptions;
18
+ if (isArray(modeEmitters.value)) {
19
+ const minLength = 0, modeEmittersCount = modeEmitters.value.length;
20
+ if (modeEmittersCount > minLength && modeEmitters.random.enable) {
21
+ emittersModeOptions = [];
22
+ const usedIndexes = new Set();
23
+ for (let i = 0; i < modeEmitters.random.count; i++) {
24
+ const idx = arrayRandomIndex(modeEmitters.value);
25
+ if (usedIndexes.has(idx) && usedIndexes.size < modeEmittersCount) {
26
+ i--;
27
+ continue;
28
+ }
29
+ usedIndexes.add(idx);
30
+ const selectedOptions = itemFromArray(modeEmitters.value, idx);
31
+ if (!selectedOptions) {
32
+ continue;
33
+ }
34
+ emittersModeOptions.push(selectedOptions);
35
+ }
36
+ }
37
+ else {
38
+ emittersModeOptions = modeEmitters.value;
39
+ }
40
+ }
41
+ else {
42
+ emittersModeOptions = modeEmitters.value;
43
+ }
44
+ const emittersOptions = emittersModeOptions, ePosition = interactivityData.mouse.clickPosition;
45
+ void executeOnSingleOrMultiple(emittersOptions, async (emitter) => {
46
+ await this._instancesManager.addEmitter(this.container, emitter, ePosition);
47
+ });
48
+ };
49
+ }
50
+ clear() {
51
+ }
52
+ init() {
53
+ }
54
+ interact(_interactivityData, delta) {
55
+ for (const emitter of this._instancesManager.getArray(this.container)) {
56
+ emitter.update(delta);
57
+ }
58
+ }
59
+ isEnabled(interactivityData, particle) {
60
+ const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity).events;
61
+ if (!mouse.clickPosition || !events.onClick.enable) {
62
+ return false;
63
+ }
64
+ return isInArray(emittersMode, events.onClick.mode);
65
+ }
66
+ loadModeOptions(options, ...sources) {
67
+ options.emitters = {
68
+ random: defaultRandomOptions,
69
+ value: [],
70
+ };
71
+ for (const source of sources) {
72
+ if (!source?.emitters) {
73
+ continue;
74
+ }
75
+ if (isArray(source.emitters)) {
76
+ for (const emitter of source.emitters) {
77
+ const tmp = new Emitter();
78
+ tmp.load(emitter);
79
+ options.emitters.value.push(tmp);
80
+ }
81
+ }
82
+ else if (Object.hasOwn(source.emitters, "value")) {
83
+ const emitterModeOptions = source.emitters;
84
+ options.emitters.random.enable = emitterModeOptions.random?.enable ?? options.emitters.random.enable;
85
+ options.emitters.random.count = emitterModeOptions.random?.count ?? options.emitters.random.count;
86
+ if (isArray(emitterModeOptions.value)) {
87
+ for (const emitter of emitterModeOptions.value) {
88
+ const tmp = new Emitter();
89
+ tmp.load(emitter);
90
+ options.emitters.value.push(tmp);
91
+ }
92
+ }
93
+ else {
94
+ const tmp = new Emitter();
95
+ tmp.load(emitterModeOptions.value);
96
+ options.emitters.value.push(tmp);
97
+ }
98
+ }
99
+ else {
100
+ const tmp = new Emitter();
101
+ tmp.load(source.emitters);
102
+ options.emitters.value.push(tmp);
103
+ }
104
+ }
105
+ }
106
+ removeEmitter(emitter) {
107
+ const index = this._instancesManager.getArray(this.container).indexOf(emitter), minIndex = 0, deleteCount = 1;
108
+ if (index >= minIndex) {
109
+ this._instancesManager.getArray(this.container).splice(index, deleteCount);
110
+ }
111
+ }
112
+ reset() {
113
+ }
114
+ }
@@ -1,16 +1,16 @@
1
- import { executeOnSingleOrMultiple, isArray, isInArray, } from "@tsparticles/engine";
1
+ import { executeOnSingleOrMultiple, isArray, } from "@tsparticles/engine";
2
2
  import { Emitter } from "./Options/Classes/Emitter.js";
3
- import { EmitterClickMode } from "./Enums/EmitterClickMode.js";
4
- import { Emitters } from "./Emitters.js";
5
3
  export class EmittersPlugin {
6
- constructor(engine) {
7
- this._engine = engine;
8
- this.id = "emitters";
4
+ id = "emitters";
5
+ _instancesManager;
6
+ constructor(instancesManager) {
7
+ this._instancesManager = instancesManager;
9
8
  }
10
- getPlugin(container) {
11
- return Promise.resolve(new Emitters(this._engine, container));
9
+ async getPlugin(container) {
10
+ const { EmittersPluginInstance } = await import("./EmittersPluginInstance.js");
11
+ return new EmittersPluginInstance(this._instancesManager, container);
12
12
  }
13
- loadOptions(options, source) {
13
+ loadOptions(_container, options, source) {
14
14
  if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
15
15
  return;
16
16
  }
@@ -21,58 +21,12 @@ export class EmittersPlugin {
21
21
  return tmp;
22
22
  });
23
23
  }
24
- const interactivityEmitters = source?.interactivity?.modes?.emitters;
25
- if (interactivityEmitters) {
26
- if (isArray(interactivityEmitters)) {
27
- options.interactivity.modes.emitters = {
28
- random: {
29
- count: 1,
30
- enable: true,
31
- },
32
- value: interactivityEmitters.map(s => {
33
- const tmp = new Emitter();
34
- tmp.load(s);
35
- return tmp;
36
- }),
37
- };
38
- }
39
- else {
40
- const emitterMode = interactivityEmitters;
41
- if (isArray(emitterMode.value)) {
42
- options.interactivity.modes.emitters = {
43
- random: {
44
- count: emitterMode.random.count,
45
- enable: emitterMode.random.enable,
46
- },
47
- value: emitterMode.value.map(s => {
48
- const tmp = new Emitter();
49
- tmp.load(s);
50
- return tmp;
51
- }),
52
- };
53
- }
54
- else {
55
- const tmp = new Emitter();
56
- tmp.load(emitterMode.value);
57
- options.interactivity.modes.emitters = {
58
- random: {
59
- count: emitterMode.random.count,
60
- enable: emitterMode.random.enable,
61
- },
62
- value: tmp,
63
- };
64
- }
65
- }
66
- }
67
24
  }
68
25
  needsPlugin(options) {
69
26
  if (!options) {
70
27
  return false;
71
28
  }
72
29
  const emitters = options.emitters;
73
- return ((isArray(emitters) && !!emitters.length) ||
74
- emitters !== undefined ||
75
- (!!options.interactivity?.events?.onClick?.mode &&
76
- isInArray(EmitterClickMode.emitter, options.interactivity.events.onClick.mode)));
30
+ return (isArray(emitters) && !!emitters.length) || emitters !== undefined;
77
31
  }
78
32
  }
@@ -0,0 +1,44 @@
1
+ import { isArray } from "@tsparticles/engine";
2
+ export class EmittersPluginInstance {
3
+ container;
4
+ _instancesManager;
5
+ constructor(instancesManager, container) {
6
+ this.container = container;
7
+ this._instancesManager = instancesManager;
8
+ this._instancesManager.initContainer(container);
9
+ }
10
+ async init() {
11
+ const emittersOptions = this.container.actualOptions.emitters;
12
+ if (isArray(emittersOptions)) {
13
+ for (const emitterOptions of emittersOptions) {
14
+ await this._instancesManager.addEmitter(this.container, emitterOptions);
15
+ }
16
+ }
17
+ else {
18
+ await this._instancesManager.addEmitter(this.container, emittersOptions);
19
+ }
20
+ }
21
+ pause() {
22
+ for (const emitter of this._instancesManager.getArray(this.container)) {
23
+ emitter.pause();
24
+ }
25
+ }
26
+ play() {
27
+ for (const emitter of this._instancesManager.getArray(this.container)) {
28
+ emitter.play();
29
+ }
30
+ }
31
+ resize() {
32
+ for (const emitter of this._instancesManager.getArray(this.container)) {
33
+ emitter.resize();
34
+ }
35
+ }
36
+ stop() {
37
+ this._instancesManager.clear(this.container);
38
+ }
39
+ update(delta) {
40
+ this._instancesManager.getArray(this.container).forEach(emitter => {
41
+ emitter.update(delta);
42
+ });
43
+ }
44
+ }
@@ -4,6 +4,19 @@ import { EmitterRate } from "./EmitterRate.js";
4
4
  import { EmitterShape } from "./EmitterShape.js";
5
5
  import { EmitterSize } from "./EmitterSize.js";
6
6
  export class Emitter {
7
+ autoPlay;
8
+ direction;
9
+ domId;
10
+ fill;
11
+ life;
12
+ name;
13
+ particles;
14
+ position;
15
+ rate;
16
+ shape;
17
+ size;
18
+ spawnColor;
19
+ startCount;
7
20
  constructor() {
8
21
  this.autoPlay = true;
9
22
  this.fill = true;
@@ -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;
@@ -1,14 +1,14 @@
1
- const shapeGeneratorss = new Map();
1
+ const shapeGenerators = new Map();
2
2
  export class ShapeManager {
3
3
  addShapeGenerator(name, generator) {
4
4
  if (!this.getShapeGenerator(name)) {
5
- shapeGeneratorss.set(name, generator);
5
+ shapeGenerators.set(name, generator);
6
6
  }
7
7
  }
8
8
  getShapeGenerator(name) {
9
- return shapeGeneratorss.get(name);
9
+ return shapeGenerators.get(name);
10
10
  }
11
11
  getSupportedShapeGenerators() {
12
- return shapeGeneratorss.keys();
12
+ return shapeGenerators.keys();
13
13
  }
14
14
  }
@@ -0,0 +1,4 @@
1
+ export const defaultRandomOptions = {
2
+ count: 1,
3
+ enable: true,
4
+ };
package/esm/index.js CHANGED
@@ -1,14 +1,28 @@
1
- export function loadEmittersPlugin(engine) {
2
- engine.checkVersion("4.0.0-alpha.2");
3
- engine.register(async (e) => {
4
- const { ShapeManager } = await import("./ShapeManager.js"), { EmittersPlugin } = await import("./EmittersPlugin.js");
1
+ export async function loadEmittersPlugin(engine) {
2
+ engine.checkVersion("4.0.0-alpha.21");
3
+ await engine.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
+ ]), instancesManager = new EmittersInstancesManager(e);
10
+ ensureInteractivityPluginLoaded(e);
5
11
  e.emitterShapeManager ??= new ShapeManager();
6
12
  e.addEmitterShapeGenerator ??= (name, generator) => {
7
13
  e.emitterShapeManager?.addShapeGenerator(name, generator);
8
14
  };
9
- const plugin = new EmittersPlugin(e);
10
- e.addPlugin(plugin);
15
+ e.addPlugin(new EmittersPlugin(instancesManager));
16
+ e.addInteractor?.("externalEmitters", async (container) => {
17
+ const { EmittersInteractor } = await import("./EmittersInteractor.js");
18
+ return new EmittersInteractor(instancesManager, container);
19
+ });
11
20
  });
12
21
  }
22
+ export function ensureEmittersPluginLoaded(e) {
23
+ if (!e.addEmitterShapeGenerator) {
24
+ throw new Error("tsParticles Emitters Plugin is not loaded");
25
+ }
26
+ }
13
27
  export * from "./EmitterShapeBase.js";
14
28
  export * from "./Enums/EmitterClickMode.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsparticles/plugin-emitters",
3
- "version": "4.0.0-alpha.2",
3
+ "version": "4.0.0-alpha.21",
4
4
  "description": "tsParticles emitters plugin",
5
5
  "homepage": "https://particles.js.org",
6
6
  "repository": {
@@ -86,7 +86,8 @@
86
86
  "./package.json": "./package.json"
87
87
  },
88
88
  "dependencies": {
89
- "@tsparticles/engine": "4.0.0-alpha.2"
89
+ "@tsparticles/engine": "4.0.0-alpha.21",
90
+ "@tsparticles/plugin-interactivity": "4.0.0-alpha.21"
90
91
  },
91
92
  "publishConfig": {
92
93
  "access": "public"