@tsparticles/engine 3.0.3 → 3.1.0

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 (124) hide show
  1. package/README.md +265 -145
  2. package/browser/Core/Canvas.js +19 -19
  3. package/browser/Core/Container.js +45 -34
  4. package/browser/Core/Engine.js +36 -20
  5. package/browser/Core/Particle.js +35 -36
  6. package/browser/Core/Particles.js +30 -24
  7. package/browser/Core/Retina.js +5 -4
  8. package/browser/Core/Utils/Circle.js +4 -3
  9. package/browser/Core/Utils/Constants.js +3 -0
  10. package/browser/Core/Utils/EventListeners.js +18 -15
  11. package/browser/Core/Utils/ExternalInteractorBase.js +1 -1
  12. package/browser/Core/Utils/InteractionManager.js +14 -6
  13. package/browser/Core/Utils/ParticlesInteractorBase.js +1 -1
  14. package/browser/Core/Utils/QuadTree.js +5 -3
  15. package/browser/Core/Utils/Vector.js +7 -2
  16. package/browser/Core/Utils/Vector3d.js +14 -9
  17. package/browser/Options/Classes/ManualParticle.js +3 -2
  18. package/browser/Options/Classes/Options.js +3 -0
  19. package/browser/Utils/CanvasUtils.js +36 -26
  20. package/browser/Utils/ColorUtils.js +124 -45
  21. package/browser/Utils/EventDispatcher.js +6 -5
  22. package/browser/Utils/HslColorManager.js +5 -5
  23. package/browser/Utils/NumberUtils.js +35 -23
  24. package/browser/Utils/RgbColorManager.js +5 -5
  25. package/browser/Utils/Utils.js +102 -19
  26. package/cjs/Core/Canvas.js +19 -19
  27. package/cjs/Core/Container.js +45 -34
  28. package/cjs/Core/Engine.js +36 -20
  29. package/cjs/Core/Particle.js +34 -35
  30. package/cjs/Core/Particles.js +30 -24
  31. package/cjs/Core/Retina.js +5 -4
  32. package/cjs/Core/Utils/Circle.js +4 -3
  33. package/cjs/Core/Utils/Constants.js +4 -1
  34. package/cjs/Core/Utils/EventListeners.js +17 -14
  35. package/cjs/Core/Utils/ExternalInteractorBase.js +1 -1
  36. package/cjs/Core/Utils/InteractionManager.js +14 -6
  37. package/cjs/Core/Utils/ParticlesInteractorBase.js +1 -1
  38. package/cjs/Core/Utils/QuadTree.js +5 -3
  39. package/cjs/Core/Utils/Vector.js +7 -2
  40. package/cjs/Core/Utils/Vector3d.js +14 -9
  41. package/cjs/Options/Classes/ManualParticle.js +3 -2
  42. package/cjs/Options/Classes/Options.js +3 -0
  43. package/cjs/Utils/CanvasUtils.js +36 -26
  44. package/cjs/Utils/ColorUtils.js +126 -45
  45. package/cjs/Utils/EventDispatcher.js +6 -5
  46. package/cjs/Utils/HslColorManager.js +5 -5
  47. package/cjs/Utils/NumberUtils.js +37 -24
  48. package/cjs/Utils/RgbColorManager.js +5 -5
  49. package/cjs/Utils/Utils.js +103 -19
  50. package/esm/Core/Canvas.js +19 -19
  51. package/esm/Core/Container.js +45 -34
  52. package/esm/Core/Engine.js +36 -20
  53. package/esm/Core/Particle.js +35 -36
  54. package/esm/Core/Particles.js +30 -24
  55. package/esm/Core/Retina.js +5 -4
  56. package/esm/Core/Utils/Circle.js +4 -3
  57. package/esm/Core/Utils/Constants.js +3 -0
  58. package/esm/Core/Utils/EventListeners.js +18 -15
  59. package/esm/Core/Utils/ExternalInteractorBase.js +1 -1
  60. package/esm/Core/Utils/InteractionManager.js +14 -6
  61. package/esm/Core/Utils/ParticlesInteractorBase.js +1 -1
  62. package/esm/Core/Utils/QuadTree.js +5 -3
  63. package/esm/Core/Utils/Vector.js +7 -2
  64. package/esm/Core/Utils/Vector3d.js +14 -9
  65. package/esm/Options/Classes/ManualParticle.js +3 -2
  66. package/esm/Options/Classes/Options.js +3 -0
  67. package/esm/Utils/CanvasUtils.js +36 -26
  68. package/esm/Utils/ColorUtils.js +124 -45
  69. package/esm/Utils/EventDispatcher.js +6 -5
  70. package/esm/Utils/HslColorManager.js +5 -5
  71. package/esm/Utils/NumberUtils.js +35 -23
  72. package/esm/Utils/RgbColorManager.js +5 -5
  73. package/esm/Utils/Utils.js +102 -19
  74. package/package.json +1 -1
  75. package/report.html +2 -2
  76. package/tsparticles.engine.js +693 -334
  77. package/tsparticles.engine.min.js +1 -1
  78. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  79. package/types/Core/Interfaces/IParticleHslAnimation.d.ts +4 -4
  80. package/types/Core/Interfaces/IParticleValueAnimation.d.ts +4 -0
  81. package/types/Core/Interfaces/IShapeDrawData.d.ts +2 -2
  82. package/types/Core/Utils/Constants.d.ts +3 -0
  83. package/types/Core/Utils/ExternalInteractorBase.d.ts +1 -1
  84. package/types/Core/Utils/InteractionManager.d.ts +1 -1
  85. package/types/Core/Utils/ParticlesInteractorBase.d.ts +1 -1
  86. package/types/Core/Utils/Point.d.ts +1 -1
  87. package/types/Options/Classes/Options.d.ts +1 -0
  88. package/types/Options/Classes/Particles/Move/Move.d.ts +1 -2
  89. package/types/Options/Classes/Particles/Move/OutModes.d.ts +1 -2
  90. package/types/Options/Interfaces/IOptions.d.ts +1 -0
  91. package/types/Options/Interfaces/Interactivity/Modes/IModes.d.ts +1 -3
  92. package/types/Types/CustomEventArgs.d.ts +2 -2
  93. package/types/Types/ExportResult.d.ts +2 -2
  94. package/types/Types/ParticlesGroups.d.ts +1 -3
  95. package/types/Types/PathOptions.d.ts +1 -3
  96. package/types/Types/ShapeData.d.ts +1 -3
  97. package/types/Utils/CanvasUtils.d.ts +3 -2
  98. package/types/Utils/ColorUtils.d.ts +5 -0
  99. package/types/Utils/NumberUtils.d.ts +2 -2
  100. package/types/Utils/Utils.d.ts +9 -6
  101. package/umd/Core/Canvas.js +19 -19
  102. package/umd/Core/Container.js +46 -35
  103. package/umd/Core/Engine.js +36 -20
  104. package/umd/Core/Particle.js +35 -36
  105. package/umd/Core/Particles.js +30 -24
  106. package/umd/Core/Retina.js +5 -4
  107. package/umd/Core/Utils/Circle.js +4 -3
  108. package/umd/Core/Utils/Constants.js +4 -1
  109. package/umd/Core/Utils/EventListeners.js +17 -14
  110. package/umd/Core/Utils/ExternalInteractorBase.js +1 -1
  111. package/umd/Core/Utils/InteractionManager.js +14 -6
  112. package/umd/Core/Utils/ParticlesInteractorBase.js +1 -1
  113. package/umd/Core/Utils/QuadTree.js +5 -3
  114. package/umd/Core/Utils/Vector.js +7 -2
  115. package/umd/Core/Utils/Vector3d.js +14 -9
  116. package/umd/Options/Classes/ManualParticle.js +3 -2
  117. package/umd/Options/Classes/Options.js +3 -0
  118. package/umd/Utils/CanvasUtils.js +36 -26
  119. package/umd/Utils/ColorUtils.js +127 -46
  120. package/umd/Utils/EventDispatcher.js +6 -5
  121. package/umd/Utils/HslColorManager.js +5 -5
  122. package/umd/Utils/NumberUtils.js +38 -25
  123. package/umd/Utils/RgbColorManager.js +5 -5
  124. package/umd/Utils/Utils.js +104 -20
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Particle = void 0;
4
4
  const NumberUtils_js_1 = require("../Utils/NumberUtils.js");
5
5
  const Utils_js_1 = require("../Utils/Utils.js");
6
+ const Constants_js_1 = require("./Utils/Constants.js");
6
7
  const ColorUtils_js_1 = require("../Utils/ColorUtils.js");
7
8
  const Interactivity_js_1 = require("../Options/Classes/Interactivity/Interactivity.js");
8
9
  const Vector_js_1 = require("./Utils/Vector.js");
9
10
  const Vector3d_js_1 = require("./Utils/Vector3d.js");
10
11
  const CanvasUtils_js_1 = require("../Utils/CanvasUtils.js");
11
- const Constants_js_1 = require("./Utils/Constants.js");
12
12
  const OptionsUtils_js_1 = require("../Utils/OptionsUtils.js");
13
+ const defaultRetryCount = 0, double = 2, half = 0.5, squareExp = 2;
13
14
  function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
14
15
  const effectData = effectOptions.options[effect];
15
16
  if (!effectData) {
@@ -34,7 +35,7 @@ function fixOutMode(data) {
34
35
  if (!(0, Utils_js_1.isInArray)(data.outMode, data.checkModes)) {
35
36
  return;
36
37
  }
37
- const diameter = data.radius * 2;
38
+ const diameter = data.radius * double;
38
39
  if (data.coord > data.maxCoord - diameter) {
39
40
  data.setCb(-data.radius);
40
41
  }
@@ -45,7 +46,7 @@ function fixOutMode(data) {
45
46
  class Particle {
46
47
  constructor(engine, id, container, position, overrideOptions, group) {
47
48
  this.container = container;
48
- this._calcPosition = (container, position, zIndex, tryCount = 0) => {
49
+ this._calcPosition = (container, position, zIndex, tryCount = defaultRetryCount) => {
49
50
  for (const [, plugin] of container.plugins) {
50
51
  const pluginPos = plugin.particlePosition !== undefined ? plugin.particlePosition(position, this) : undefined;
51
52
  if (pluginPos) {
@@ -79,7 +80,8 @@ class Particle {
79
80
  fixVertical(outModes.top ?? outModes.default);
80
81
  fixVertical(outModes.bottom ?? outModes.default);
81
82
  if (this._checkOverlap(pos, tryCount)) {
82
- return this._calcPosition(container, undefined, zIndex, tryCount + 1);
83
+ const increment = 1;
84
+ return this._calcPosition(container, undefined, zIndex, tryCount + increment);
83
85
  }
84
86
  return pos;
85
87
  };
@@ -88,9 +90,9 @@ class Particle {
88
90
  if (moveOptions.direction === "inside" || moveOptions.direction === "outside") {
89
91
  return res;
90
92
  }
91
- const rad = (Math.PI / 180) * (0, NumberUtils_js_1.getRangeValue)(moveOptions.angle.value), radOffset = (Math.PI / 180) * (0, NumberUtils_js_1.getRangeValue)(moveOptions.angle.offset), range = {
92
- left: radOffset - rad * 0.5,
93
- right: radOffset + rad * 0.5,
93
+ const rad = (0, NumberUtils_js_1.degToRad)((0, NumberUtils_js_1.getRangeValue)(moveOptions.angle.value)), radOffset = (0, NumberUtils_js_1.degToRad)((0, NumberUtils_js_1.getRangeValue)(moveOptions.angle.offset)), range = {
94
+ left: radOffset - rad * half,
95
+ right: radOffset + rad * half,
94
96
  };
95
97
  if (!moveOptions.straight) {
96
98
  res.angle += (0, NumberUtils_js_1.randomInRange)((0, NumberUtils_js_1.setRangeValue)(range.left, range.right));
@@ -100,7 +102,7 @@ class Particle {
100
102
  }
101
103
  return res;
102
104
  };
103
- this._checkOverlap = (pos, tryCount = 0) => {
105
+ this._checkOverlap = (pos, tryCount = defaultRetryCount) => {
104
106
  const collisionsOptions = this.options.collisions, radius = this.getRadius();
105
107
  if (!collisionsOptions.enable) {
106
108
  return false;
@@ -109,8 +111,8 @@ class Particle {
109
111
  if (overlapOptions.enable) {
110
112
  return false;
111
113
  }
112
- const retries = overlapOptions.retries;
113
- if (retries >= 0 && tryCount > retries) {
114
+ const retries = overlapOptions.retries, minRetries = 0;
115
+ if (retries >= minRetries && tryCount > retries) {
114
116
  throw new Error(`${Constants_js_1.errorPrefix} particle is overlapping and can't be placed`);
115
117
  }
116
118
  return !!this.container.particles.find((particle) => (0, NumberUtils_js_1.getDistance)(pos, particle.position) < radius + particle.getRadius());
@@ -119,7 +121,7 @@ class Particle {
119
121
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
120
122
  return color;
121
123
  }
122
- const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1, backSum = this.roll.horizontal ? Math.PI * 0.5 : 0, rolled = Math.floor(((this.roll.angle ?? 0) + backSum) / (Math.PI / backFactor)) % 2;
124
+ const rollFactor = 1, none = 0, backFactor = this.roll.horizontal && this.roll.vertical ? double * rollFactor : rollFactor, backSum = this.roll.horizontal ? Math.PI * half : none, rolled = Math.floor(((this.roll.angle ?? none) + backSum) / (Math.PI / backFactor)) % double;
123
125
  if (!rolled) {
124
126
  return color;
125
127
  }
@@ -132,13 +134,13 @@ class Particle {
132
134
  return color;
133
135
  };
134
136
  this._initPosition = (position) => {
135
- const container = this.container, zIndexValue = (0, NumberUtils_js_1.getRangeValue)(this.options.zIndex.value);
136
- this.position = this._calcPosition(container, position, (0, NumberUtils_js_1.clamp)(zIndexValue, 0, container.zLayers));
137
+ const container = this.container, zIndexValue = (0, NumberUtils_js_1.getRangeValue)(this.options.zIndex.value), minZ = 0;
138
+ this.position = this._calcPosition(container, position, (0, NumberUtils_js_1.clamp)(zIndexValue, minZ, container.zLayers));
137
139
  this.initialPosition = this.position.copy();
138
- const canvasSize = container.canvas.size;
140
+ const canvasSize = container.canvas.size, defaultRadius = 0;
139
141
  this.moveCenter = {
140
142
  ...(0, Utils_js_1.getPosition)(this.options.move.center, canvasSize),
141
- radius: this.options.move.center.radius ?? 0,
143
+ radius: this.options.move.center.radius ?? defaultRadius,
142
144
  mode: this.options.move.center.mode ?? "percent",
143
145
  };
144
146
  this.direction = (0, NumberUtils_js_1.getParticleDirectionAngle)(this.options.move.direction, this.position, this.moveCenter);
@@ -163,14 +165,14 @@ class Particle {
163
165
  this.bubble.inRange = false;
164
166
  this.slow.inRange = false;
165
167
  const container = this.container, pathGenerator = this.pathGenerator, shapeDrawer = container.shapeDrawers.get(this.shape);
166
- shapeDrawer && shapeDrawer.particleDestroy && shapeDrawer.particleDestroy(this);
168
+ shapeDrawer?.particleDestroy?.(this);
167
169
  for (const [, plugin] of container.plugins) {
168
- plugin.particleDestroyed && plugin.particleDestroyed(this, override);
170
+ plugin.particleDestroyed?.(this, override);
169
171
  }
170
172
  for (const updater of container.particles.updaters) {
171
- updater.particleDestroyed && updater.particleDestroyed(this, override);
173
+ updater.particleDestroyed?.(this, override);
172
174
  }
173
- pathGenerator && pathGenerator.reset(this);
175
+ pathGenerator?.reset(this);
174
176
  this._engine.dispatchEvent("particleDestroyed", {
175
177
  container: this.container,
176
178
  data: {
@@ -189,7 +191,7 @@ class Particle {
189
191
  return this._getRollColor(this.bubble.color ?? (0, ColorUtils_js_1.getHslFromAnimation)(this.color));
190
192
  }
191
193
  getMass() {
192
- return this.getRadius() ** 2 * Math.PI * 0.5;
194
+ return this.getRadius() ** squareExp * Math.PI * half;
193
195
  }
194
196
  getPosition() {
195
197
  return {
@@ -228,14 +230,14 @@ class Particle {
228
230
  this.shape = (0, Utils_js_1.itemFromSingleOrMultiple)(shapeType, this.id, reduceDuplicates);
229
231
  const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
230
232
  if (overrideOptions) {
231
- if (overrideOptions.effect && overrideOptions.effect.type) {
233
+ if (overrideOptions.effect?.type) {
232
234
  const overrideEffectType = overrideOptions.effect.type, effect = (0, Utils_js_1.itemFromSingleOrMultiple)(overrideEffectType, this.id, reduceDuplicates);
233
235
  if (effect) {
234
236
  this.effect = effect;
235
237
  effectOptions.load(overrideOptions.effect);
236
238
  }
237
239
  }
238
- if (overrideOptions.shape && overrideOptions.shape.type) {
240
+ if (overrideOptions.shape?.type) {
239
241
  const overrideShapeType = overrideOptions.shape.type, shape = (0, Utils_js_1.itemFromSingleOrMultiple)(overrideShapeType, this.id, reduceDuplicates);
240
242
  if (shape) {
241
243
  this.shape = shape;
@@ -264,7 +266,7 @@ class Particle {
264
266
  this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
265
267
  this.options = particlesOptions;
266
268
  const pathOptions = this.options.move.path;
267
- this.pathDelay = (0, NumberUtils_js_1.getRangeValue)(pathOptions.delay.value) * 1000;
269
+ this.pathDelay = (0, NumberUtils_js_1.getRangeValue)(pathOptions.delay.value) * Constants_js_1.millisecondsToSeconds;
268
270
  if (pathOptions.generator) {
269
271
  this.pathGenerator = this._engine.getPathGenerator(pathOptions.generator);
270
272
  if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
@@ -283,7 +285,8 @@ class Particle {
283
285
  this._initPosition(position);
284
286
  this.initialVelocity = this._calculateVelocity();
285
287
  this.velocity = this.initialVelocity.copy();
286
- this.moveDecay = 1 - (0, NumberUtils_js_1.getRangeValue)(this.options.move.decay);
288
+ const decayOffset = 1;
289
+ this.moveDecay = decayOffset - (0, NumberUtils_js_1.getRangeValue)(this.options.move.decay);
287
290
  const particles = container.particles;
288
291
  particles.setLastZIndex(this.position.z);
289
292
  this.zIndexFactor = this.position.z / container.zLayers;
@@ -295,7 +298,7 @@ class Particle {
295
298
  container.effectDrawers.set(this.effect, effectDrawer);
296
299
  }
297
300
  }
298
- if (effectDrawer && effectDrawer.loadEffect) {
301
+ if (effectDrawer?.loadEffect) {
299
302
  effectDrawer.loadEffect(this);
300
303
  }
301
304
  let shapeDrawer = container.shapeDrawers.get(this.shape);
@@ -305,7 +308,7 @@ class Particle {
305
308
  container.shapeDrawers.set(this.shape, shapeDrawer);
306
309
  }
307
310
  }
308
- if (shapeDrawer && shapeDrawer.loadShape) {
311
+ if (shapeDrawer?.loadShape) {
309
312
  shapeDrawer.loadShape(this);
310
313
  }
311
314
  const sideCountFunc = shapeDrawer?.getSidesCount;
@@ -318,16 +321,12 @@ class Particle {
318
321
  updater.init(this);
319
322
  }
320
323
  for (const mover of particles.movers) {
321
- mover.init && mover.init(this);
322
- }
323
- if (effectDrawer && effectDrawer.particleInit) {
324
- effectDrawer.particleInit(container, this);
325
- }
326
- if (shapeDrawer && shapeDrawer.particleInit) {
327
- shapeDrawer.particleInit(container, this);
324
+ mover.init?.(this);
328
325
  }
326
+ effectDrawer?.particleInit?.(container, this);
327
+ shapeDrawer?.particleInit?.(container, this);
329
328
  for (const [, plugin] of container.plugins) {
330
- plugin.particleCreated && plugin.particleCreated(this);
329
+ plugin.particleCreated?.(this);
331
330
  }
332
331
  }
333
332
  isInsideCanvas() {
@@ -342,7 +341,7 @@ class Particle {
342
341
  }
343
342
  reset() {
344
343
  for (const updater of this.container.particles.updaters) {
345
- updater.reset && updater.reset(this);
344
+ updater.reset?.(this);
346
345
  }
347
346
  }
348
347
  }
@@ -8,7 +8,7 @@ const Point_js_1 = require("./Utils/Point.js");
8
8
  const QuadTree_js_1 = require("./Utils/QuadTree.js");
9
9
  const Rectangle_js_1 = require("./Utils/Rectangle.js");
10
10
  const Constants_js_1 = require("./Utils/Constants.js");
11
- const qTreeCapacity = 4;
11
+ const qTreeCapacity = 4, squareExp = 2, defaultRemoveQuantity = 1;
12
12
  const qTreeRectangle = (canvasSize) => {
13
13
  const { height, width } = canvasSize, posOffset = -0.25, sizeFactor = 1.5;
14
14
  return new Rectangle_js_1.Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
@@ -31,7 +31,7 @@ class Particles {
31
31
  }
32
32
  return;
33
33
  }
34
- const densityFactor = this._initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value > 0 ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount, particlesCount = Math.min(this.count, this.filter((t) => t.group === group).length);
34
+ const densityFactor = this._initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, minLimit = 0, optParticlesLimit = numberOptions.limit.value > minLimit ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount, particlesCount = Math.min(this.count, this.filter((t) => t.group === group).length);
35
35
  if (group === undefined) {
36
36
  this._limit = numberOptions.limit.value * densityFactor;
37
37
  }
@@ -46,12 +46,12 @@ class Particles {
46
46
  }
47
47
  };
48
48
  this._initDensityFactor = (densityOptions) => {
49
- const container = this._container;
49
+ const container = this._container, defaultFactor = 1;
50
50
  if (!container.canvas.element || !densityOptions.enable) {
51
- return 1;
51
+ return defaultFactor;
52
52
  }
53
53
  const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio;
54
- return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** 2);
54
+ return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp);
55
55
  };
56
56
  this._pushParticle = (position, overrideOptions, group, initializer) => {
57
57
  try {
@@ -82,7 +82,6 @@ class Particles {
82
82
  }
83
83
  catch (e) {
84
84
  (0, Utils_js_1.getLogger)().warning(`${Constants_js_1.errorPrefix} adding particle: ${e}`);
85
- return;
86
85
  }
87
86
  };
88
87
  this._removeParticle = (index, group, override) => {
@@ -90,9 +89,9 @@ class Particles {
90
89
  if (!particle || particle.group !== group) {
91
90
  return false;
92
91
  }
93
- const zIdx = this._zArray.indexOf(particle);
94
- this._array.splice(index, 1);
95
- this._zArray.splice(zIdx, 1);
92
+ const zIdx = this._zArray.indexOf(particle), deleteCount = 1;
93
+ this._array.splice(index, deleteCount);
94
+ this._zArray.splice(zIdx, deleteCount);
96
95
  particle.destroy(override);
97
96
  this._engine.dispatchEvent("particleRemoved", {
98
97
  container: this._container,
@@ -129,11 +128,11 @@ class Particles {
129
128
  }
130
129
  }
131
130
  addParticle(position, overrideOptions, group, initializer) {
132
- const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count;
133
- if (limit > 0) {
131
+ const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count, minLimit = 0;
132
+ if (limit > minLimit) {
134
133
  if (limitOptions.mode === "delete") {
135
- const countToRemove = currentCount + 1 - limit;
136
- if (countToRemove > 0) {
134
+ const countOffset = 1, minCount = 0, countToRemove = currentCount + countOffset - limit;
135
+ if (countToRemove > minCount) {
137
136
  this.removeQuantity(countToRemove);
138
137
  }
139
138
  }
@@ -224,22 +223,26 @@ class Particles {
224
223
  remove(particle, group, override) {
225
224
  this.removeAt(this._array.indexOf(particle), undefined, group, override);
226
225
  }
227
- removeAt(index, quantity = 1, group, override) {
228
- if (index < 0 || index > this.count) {
226
+ removeAt(index, quantity = defaultRemoveQuantity, group, override) {
227
+ const minIndex = 0;
228
+ if (index < minIndex || index > this.count) {
229
229
  return;
230
230
  }
231
231
  let deleted = 0;
232
232
  for (let i = index; deleted < quantity && i < this.count; i++) {
233
- this._removeParticle(i--, group, override) && deleted++;
233
+ if (this._removeParticle(i--, group, override)) {
234
+ deleted++;
235
+ }
234
236
  }
235
237
  }
236
238
  removeQuantity(quantity, group) {
237
- this.removeAt(0, quantity, group);
239
+ const defaultIndex = 0;
240
+ this.removeAt(defaultIndex, quantity, group);
238
241
  }
239
242
  setDensity() {
240
- const options = this._container.actualOptions, groups = options.particles.groups;
243
+ const options = this._container.actualOptions, groups = options.particles.groups, manualCount = 0;
241
244
  for (const group in groups) {
242
- this._applyDensity(groups[group], 0, group);
245
+ this._applyDensity(groups[group], manualCount, group);
243
246
  }
244
247
  this._applyDensity(options.particles, options.manualParticles.length);
245
248
  }
@@ -257,7 +260,7 @@ class Particles {
257
260
  pathGenerator.update();
258
261
  }
259
262
  for (const [, plugin] of container.plugins) {
260
- plugin.update && (await plugin.update(delta));
263
+ await plugin.update?.(delta);
261
264
  }
262
265
  const resizeFactor = this._resizeFactor;
263
266
  for (const particle of this._array) {
@@ -268,15 +271,17 @@ class Particles {
268
271
  particle.initialPosition.y *= resizeFactor.height;
269
272
  }
270
273
  particle.ignoresResizeRatio = false;
271
- await this._interactionManager.reset(particle);
274
+ this._interactionManager.reset(particle);
272
275
  for (const [, plugin] of this._container.plugins) {
273
276
  if (particle.destroyed) {
274
277
  break;
275
278
  }
276
- plugin.particleUpdate && plugin.particleUpdate(particle, delta);
279
+ plugin.particleUpdate?.(particle, delta);
277
280
  }
278
281
  for (const mover of this.movers) {
279
- mover.isEnabled(particle) && mover.move(particle, delta);
282
+ if (mover.isEnabled(particle)) {
283
+ mover.move(particle, delta);
284
+ }
280
285
  }
281
286
  if (particle.destroyed) {
282
287
  particlesToDelete.add(particle);
@@ -311,7 +316,8 @@ class Particles {
311
316
  if (this._needsSort) {
312
317
  const zArray = this._zArray;
313
318
  zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
314
- this._lastZIndex = zArray[zArray.length - 1].position.z;
319
+ const lengthOffset = 1;
320
+ this._lastZIndex = zArray[zArray.length - lengthOffset].position.z;
315
321
  this._needsSort = false;
316
322
  }
317
323
  }
@@ -3,16 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Retina = void 0;
4
4
  const NumberUtils_js_1 = require("../Utils/NumberUtils.js");
5
5
  const Utils_js_1 = require("../Utils/Utils.js");
6
+ const defaultRatio = 1, defaultReduceFactor = 1;
6
7
  class Retina {
7
8
  constructor(container) {
8
9
  this.container = container;
9
- this.pixelRatio = 1;
10
- this.reduceFactor = 1;
10
+ this.pixelRatio = defaultRatio;
11
+ this.reduceFactor = defaultReduceFactor;
11
12
  }
12
13
  init() {
13
14
  const container = this.container, options = container.actualOptions;
14
- this.pixelRatio = !options.detectRetina || (0, Utils_js_1.isSsr)() ? 1 : window.devicePixelRatio;
15
- this.reduceFactor = 1;
15
+ this.pixelRatio = !options.detectRetina || (0, Utils_js_1.isSsr)() ? defaultRatio : window.devicePixelRatio;
16
+ this.reduceFactor = defaultReduceFactor;
16
17
  const ratio = this.pixelRatio, canvas = container.canvas;
17
18
  if (canvas.element) {
18
19
  const element = canvas.element;
@@ -4,6 +4,7 @@ exports.Circle = void 0;
4
4
  const Range_js_1 = require("./Range.js");
5
5
  const Rectangle_js_1 = require("./Rectangle.js");
6
6
  const NumberUtils_js_1 = require("../../Utils/NumberUtils.js");
7
+ const squareExp = 2;
7
8
  class Circle extends Range_js_1.Range {
8
9
  constructor(x, y, radius) {
9
10
  super(x, y);
@@ -15,12 +16,12 @@ class Circle extends Range_js_1.Range {
15
16
  intersects(range) {
16
17
  const pos1 = this.position, pos2 = range.position, distPos = { x: Math.abs(pos2.x - pos1.x), y: Math.abs(pos2.y - pos1.y) }, r = this.radius;
17
18
  if (range instanceof Circle) {
18
- const rSum = r + range.radius, dist = Math.sqrt(distPos.x ** 2 + distPos.y ** 2);
19
+ const rSum = r + range.radius, dist = Math.sqrt(distPos.x ** squareExp + distPos.y ** squareExp);
19
20
  return rSum > dist;
20
21
  }
21
22
  else if (range instanceof Rectangle_js_1.Rectangle) {
22
- const { width, height } = range.size, edges = Math.pow(distPos.x - width, 2) + Math.pow(distPos.y - height, 2);
23
- return (edges <= r ** 2 ||
23
+ const { width, height } = range.size, edges = Math.pow(distPos.x - width, squareExp) + Math.pow(distPos.y - height, squareExp);
24
+ return (edges <= r ** squareExp ||
24
25
  (distPos.x <= r + width && distPos.y <= r + height) ||
25
26
  distPos.x <= width ||
26
27
  distPos.y <= height);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.errorPrefix = exports.visibilityChangeEvent = exports.resizeEvent = exports.touchCancelEvent = exports.touchMoveEvent = exports.touchEndEvent = exports.touchStartEvent = exports.mouseMoveEvent = exports.mouseOutEvent = exports.mouseLeaveEvent = exports.mouseUpEvent = exports.mouseDownEvent = exports.generatedAttribute = void 0;
3
+ exports.millisecondsToSeconds = exports.halfRandom = exports.percentDenominator = exports.errorPrefix = exports.visibilityChangeEvent = exports.resizeEvent = exports.touchCancelEvent = exports.touchMoveEvent = exports.touchEndEvent = exports.touchStartEvent = exports.mouseMoveEvent = exports.mouseOutEvent = exports.mouseLeaveEvent = exports.mouseUpEvent = exports.mouseDownEvent = exports.generatedAttribute = void 0;
4
4
  exports.generatedAttribute = "generated";
5
5
  exports.mouseDownEvent = "pointerdown";
6
6
  exports.mouseUpEvent = "pointerup";
@@ -14,3 +14,6 @@ exports.touchCancelEvent = "touchcancel";
14
14
  exports.resizeEvent = "resize";
15
15
  exports.visibilityChangeEvent = "visibilitychange";
16
16
  exports.errorPrefix = "tsParticles - Error";
17
+ exports.percentDenominator = 100;
18
+ exports.halfRandom = 0.5;
19
+ exports.millisecondsToSeconds = 1000;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EventListeners = void 0;
4
4
  const Utils_js_1 = require("../../Utils/Utils.js");
5
5
  const Constants_js_1 = require("./Constants.js");
6
+ const double = 2;
6
7
  function manageListener(element, event, handler, add, options) {
7
8
  if (add) {
8
9
  let addOptions = { passive: true };
@@ -35,13 +36,14 @@ class EventListeners {
35
36
  (0, Utils_js_1.executeOnSingleOrMultiple)(onClick.mode, (mode) => this.container.handleClickMode(mode));
36
37
  }
37
38
  if (e.type === "touchend") {
38
- setTimeout(() => this._mouseTouchFinish(), 500);
39
+ const touchDelay = 500;
40
+ setTimeout(() => this._mouseTouchFinish(), touchDelay);
39
41
  }
40
42
  };
41
43
  this._handleThemeChange = (e) => {
42
44
  const mediaEvent = e, container = this.container, options = container.options, defaultThemes = options.defaultThemes, themeName = mediaEvent.matches ? defaultThemes.dark : defaultThemes.light, theme = options.themes.find((theme) => theme.name === themeName);
43
45
  if (theme && theme.default.auto) {
44
- container.loadTheme(themeName);
46
+ void container.loadTheme(themeName);
45
47
  }
46
48
  };
47
49
  this._handleVisibilityChange = () => {
@@ -64,15 +66,16 @@ class EventListeners {
64
66
  }
65
67
  }
66
68
  };
67
- this._handleWindowResize = async () => {
69
+ this._handleWindowResize = () => {
68
70
  if (this._resizeTimeout) {
69
71
  clearTimeout(this._resizeTimeout);
70
72
  delete this._resizeTimeout;
71
73
  }
72
- this._resizeTimeout = setTimeout(async () => {
74
+ const handleResize = async () => {
73
75
  const canvas = this.container.canvas;
74
- canvas && (await canvas.windowResize());
75
- }, this.container.actualOptions.interactivity.events.resize.delay * 1000);
76
+ await canvas?.windowResize();
77
+ };
78
+ this._resizeTimeout = setTimeout(() => void handleResize(), this.container.actualOptions.interactivity.events.resize.delay * Constants_js_1.millisecondsToSeconds);
76
79
  };
77
80
  this._manageInteractivityListeners = (mouseLeaveTmpEvent, add) => {
78
81
  const handlers = this._handlers, container = this.container, options = container.actualOptions;
@@ -158,12 +161,12 @@ class EventListeners {
158
161
  delete this._resizeObserver;
159
162
  }
160
163
  else if (!this._resizeObserver && add && canvasEl) {
161
- this._resizeObserver = new ResizeObserver(async (entries) => {
164
+ this._resizeObserver = new ResizeObserver((entries) => {
162
165
  const entry = entries.find((e) => e.target === canvasEl);
163
166
  if (!entry) {
164
167
  return;
165
168
  }
166
- await this._handleWindowResize();
169
+ this._handleWindowResize();
167
170
  });
168
171
  this._resizeObserver.observe(canvasEl);
169
172
  }
@@ -214,7 +217,7 @@ class EventListeners {
214
217
  };
215
218
  this._mouseTouchMove = (e) => {
216
219
  const container = this.container, options = container.actualOptions, interactivity = container.interactivity, canvasEl = container.canvas.element;
217
- if (!interactivity || !interactivity.element) {
220
+ if (!interactivity?.element) {
218
221
  return;
219
222
  }
220
223
  interactivity.mouse.inside = true;
@@ -236,8 +239,8 @@ class EventListeners {
236
239
  if (source && target && canvasEl) {
237
240
  const sourceRect = source.getBoundingClientRect(), targetRect = target.getBoundingClientRect(), canvasRect = canvasEl.getBoundingClientRect();
238
241
  pos = {
239
- x: mouseEvent.offsetX + 2 * sourceRect.left - (targetRect.left + canvasRect.left),
240
- y: mouseEvent.offsetY + 2 * sourceRect.top - (targetRect.top + canvasRect.top),
242
+ x: mouseEvent.offsetX + double * sourceRect.left - (targetRect.left + canvasRect.left),
243
+ y: mouseEvent.offsetY + double * sourceRect.top - (targetRect.top + canvasRect.top),
241
244
  };
242
245
  }
243
246
  else {
@@ -257,10 +260,10 @@ class EventListeners {
257
260
  else {
258
261
  this._canPush = e.type !== "touchmove";
259
262
  if (canvasEl) {
260
- const touchEvent = e, lastTouch = touchEvent.touches[touchEvent.touches.length - 1], canvasRect = canvasEl.getBoundingClientRect();
263
+ const touchEvent = e, lengthOffset = 1, lastTouch = touchEvent.touches[touchEvent.touches.length - lengthOffset], canvasRect = canvasEl.getBoundingClientRect(), defaultCoordinate = 0;
261
264
  pos = {
262
- x: lastTouch.clientX - (canvasRect.left ?? 0),
263
- y: lastTouch.clientY - (canvasRect.top ?? 0),
265
+ x: lastTouch.clientX - (canvasRect.left ?? defaultCoordinate),
266
+ y: lastTouch.clientY - (canvasRect.top ?? defaultCoordinate),
264
267
  };
265
268
  }
266
269
  }
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ExternalInteractorBase = void 0;
4
4
  class ExternalInteractorBase {
5
5
  constructor(container) {
6
- this.container = container;
7
6
  this.type = "external";
7
+ this.container = container;
8
8
  }
9
9
  }
10
10
  exports.ExternalInteractorBase = ExternalInteractorBase;
@@ -11,12 +11,14 @@ class InteractionManager {
11
11
  }
12
12
  async externalInteract(delta) {
13
13
  for (const interactor of this._externalInteractors) {
14
- interactor.isEnabled() && (await interactor.interact(delta));
14
+ if (interactor.isEnabled()) {
15
+ await interactor.interact(delta);
16
+ }
15
17
  }
16
18
  }
17
19
  handleClickMode(mode) {
18
20
  for (const interactor of this._externalInteractors) {
19
- interactor.handleClickMode && interactor.handleClickMode(mode);
21
+ interactor.handleClickMode?.(mode);
20
22
  }
21
23
  }
22
24
  init() {
@@ -39,15 +41,21 @@ class InteractionManager {
39
41
  interactor.clear(particle, delta);
40
42
  }
41
43
  for (const interactor of this._particleInteractors) {
42
- interactor.isEnabled(particle) && (await interactor.interact(particle, delta));
44
+ if (interactor.isEnabled(particle)) {
45
+ await interactor.interact(particle, delta);
46
+ }
43
47
  }
44
48
  }
45
- async reset(particle) {
49
+ reset(particle) {
46
50
  for (const interactor of this._externalInteractors) {
47
- interactor.isEnabled() && interactor.reset(particle);
51
+ if (interactor.isEnabled()) {
52
+ interactor.reset(particle);
53
+ }
48
54
  }
49
55
  for (const interactor of this._particleInteractors) {
50
- interactor.isEnabled(particle) && interactor.reset(particle);
56
+ if (interactor.isEnabled(particle)) {
57
+ interactor.reset(particle);
58
+ }
51
59
  }
52
60
  }
53
61
  }
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ParticlesInteractorBase = void 0;
4
4
  class ParticlesInteractorBase {
5
5
  constructor(container) {
6
- this.container = container;
7
6
  this.type = "particles";
7
+ this.container = container;
8
8
  }
9
9
  }
10
10
  exports.ParticlesInteractorBase = ParticlesInteractorBase;
@@ -4,14 +4,16 @@ exports.QuadTree = void 0;
4
4
  const Circle_js_1 = require("./Circle.js");
5
5
  const Rectangle_js_1 = require("./Rectangle.js");
6
6
  const NumberUtils_js_1 = require("../../Utils/NumberUtils.js");
7
+ const half = 0.5, double = 2, subdivideCount = 4;
7
8
  class QuadTree {
8
9
  constructor(rectangle, capacity) {
9
10
  this.rectangle = rectangle;
10
11
  this.capacity = capacity;
11
12
  this._subdivide = () => {
12
13
  const { x, y } = this.rectangle.position, { width, height } = this.rectangle.size, { capacity } = this;
13
- for (let i = 0; i < 4; i++) {
14
- this._subs.push(new QuadTree(new Rectangle_js_1.Rectangle(x + width * 0.5 * (i % 2), y + height * 0.5 * (Math.round(i * 0.5) - (i % 2)), width * 0.5, height * 0.5), capacity));
14
+ for (let i = 0; i < subdivideCount; i++) {
15
+ const fixedIndex = i % double;
16
+ this._subs.push(new QuadTree(new Rectangle_js_1.Rectangle(x + width * half * fixedIndex, y + height * half * (Math.round(i * half) - fixedIndex), width * half, height * half), capacity));
15
17
  }
16
18
  this._divided = true;
17
19
  };
@@ -33,7 +35,7 @@ class QuadTree {
33
35
  return this._subs.some((sub) => sub.insert(point));
34
36
  }
35
37
  query(range, check, found) {
36
- const res = found || [];
38
+ const res = found ?? [];
37
39
  if (!range.intersects(this.rectangle)) {
38
40
  return [];
39
41
  }
@@ -2,12 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Vector = void 0;
4
4
  const Vector3d_js_1 = require("./Vector3d.js");
5
+ const origin = {
6
+ x: 0,
7
+ y: 0,
8
+ z: 0,
9
+ };
5
10
  class Vector extends Vector3d_js_1.Vector3d {
6
11
  constructor(xOrCoords, y) {
7
- super(xOrCoords, y, 0);
12
+ super(xOrCoords, y, origin.z);
8
13
  }
9
14
  static get origin() {
10
- return Vector.create(0, 0);
15
+ return Vector.create(origin.x, origin.y);
11
16
  }
12
17
  static clone(source) {
13
18
  return Vector.create(source.x, source.y);