@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
@@ -4,7 +4,7 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "../Utils/NumberUtils.js", "../Utils/Utils.js", "../Utils/ColorUtils.js", "../Options/Classes/Interactivity/Interactivity.js", "./Utils/Vector.js", "./Utils/Vector3d.js", "../Utils/CanvasUtils.js", "./Utils/Constants.js", "../Utils/OptionsUtils.js"], factory);
7
+ define(["require", "exports", "../Utils/NumberUtils.js", "../Utils/Utils.js", "./Utils/Constants.js", "../Utils/ColorUtils.js", "../Options/Classes/Interactivity/Interactivity.js", "./Utils/Vector.js", "./Utils/Vector3d.js", "../Utils/CanvasUtils.js", "../Utils/OptionsUtils.js"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
@@ -12,13 +12,14 @@
12
12
  exports.Particle = void 0;
13
13
  const NumberUtils_js_1 = require("../Utils/NumberUtils.js");
14
14
  const Utils_js_1 = require("../Utils/Utils.js");
15
+ const Constants_js_1 = require("./Utils/Constants.js");
15
16
  const ColorUtils_js_1 = require("../Utils/ColorUtils.js");
16
17
  const Interactivity_js_1 = require("../Options/Classes/Interactivity/Interactivity.js");
17
18
  const Vector_js_1 = require("./Utils/Vector.js");
18
19
  const Vector3d_js_1 = require("./Utils/Vector3d.js");
19
20
  const CanvasUtils_js_1 = require("../Utils/CanvasUtils.js");
20
- const Constants_js_1 = require("./Utils/Constants.js");
21
21
  const OptionsUtils_js_1 = require("../Utils/OptionsUtils.js");
22
+ const defaultRetryCount = 0, double = 2, half = 0.5, squareExp = 2;
22
23
  function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
23
24
  const effectData = effectOptions.options[effect];
24
25
  if (!effectData) {
@@ -43,7 +44,7 @@
43
44
  if (!(0, Utils_js_1.isInArray)(data.outMode, data.checkModes)) {
44
45
  return;
45
46
  }
46
- const diameter = data.radius * 2;
47
+ const diameter = data.radius * double;
47
48
  if (data.coord > data.maxCoord - diameter) {
48
49
  data.setCb(-data.radius);
49
50
  }
@@ -54,7 +55,7 @@
54
55
  class Particle {
55
56
  constructor(engine, id, container, position, overrideOptions, group) {
56
57
  this.container = container;
57
- this._calcPosition = (container, position, zIndex, tryCount = 0) => {
58
+ this._calcPosition = (container, position, zIndex, tryCount = defaultRetryCount) => {
58
59
  for (const [, plugin] of container.plugins) {
59
60
  const pluginPos = plugin.particlePosition !== undefined ? plugin.particlePosition(position, this) : undefined;
60
61
  if (pluginPos) {
@@ -88,7 +89,8 @@
88
89
  fixVertical(outModes.top ?? outModes.default);
89
90
  fixVertical(outModes.bottom ?? outModes.default);
90
91
  if (this._checkOverlap(pos, tryCount)) {
91
- return this._calcPosition(container, undefined, zIndex, tryCount + 1);
92
+ const increment = 1;
93
+ return this._calcPosition(container, undefined, zIndex, tryCount + increment);
92
94
  }
93
95
  return pos;
94
96
  };
@@ -97,9 +99,9 @@
97
99
  if (moveOptions.direction === "inside" || moveOptions.direction === "outside") {
98
100
  return res;
99
101
  }
100
- 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 = {
101
- left: radOffset - rad * 0.5,
102
- right: radOffset + rad * 0.5,
102
+ 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 = {
103
+ left: radOffset - rad * half,
104
+ right: radOffset + rad * half,
103
105
  };
104
106
  if (!moveOptions.straight) {
105
107
  res.angle += (0, NumberUtils_js_1.randomInRange)((0, NumberUtils_js_1.setRangeValue)(range.left, range.right));
@@ -109,7 +111,7 @@
109
111
  }
110
112
  return res;
111
113
  };
112
- this._checkOverlap = (pos, tryCount = 0) => {
114
+ this._checkOverlap = (pos, tryCount = defaultRetryCount) => {
113
115
  const collisionsOptions = this.options.collisions, radius = this.getRadius();
114
116
  if (!collisionsOptions.enable) {
115
117
  return false;
@@ -118,8 +120,8 @@
118
120
  if (overlapOptions.enable) {
119
121
  return false;
120
122
  }
121
- const retries = overlapOptions.retries;
122
- if (retries >= 0 && tryCount > retries) {
123
+ const retries = overlapOptions.retries, minRetries = 0;
124
+ if (retries >= minRetries && tryCount > retries) {
123
125
  throw new Error(`${Constants_js_1.errorPrefix} particle is overlapping and can't be placed`);
124
126
  }
125
127
  return !!this.container.particles.find((particle) => (0, NumberUtils_js_1.getDistance)(pos, particle.position) < radius + particle.getRadius());
@@ -128,7 +130,7 @@
128
130
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
129
131
  return color;
130
132
  }
131
- 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;
133
+ 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;
132
134
  if (!rolled) {
133
135
  return color;
134
136
  }
@@ -141,13 +143,13 @@
141
143
  return color;
142
144
  };
143
145
  this._initPosition = (position) => {
144
- const container = this.container, zIndexValue = (0, NumberUtils_js_1.getRangeValue)(this.options.zIndex.value);
145
- this.position = this._calcPosition(container, position, (0, NumberUtils_js_1.clamp)(zIndexValue, 0, container.zLayers));
146
+ const container = this.container, zIndexValue = (0, NumberUtils_js_1.getRangeValue)(this.options.zIndex.value), minZ = 0;
147
+ this.position = this._calcPosition(container, position, (0, NumberUtils_js_1.clamp)(zIndexValue, minZ, container.zLayers));
146
148
  this.initialPosition = this.position.copy();
147
- const canvasSize = container.canvas.size;
149
+ const canvasSize = container.canvas.size, defaultRadius = 0;
148
150
  this.moveCenter = {
149
151
  ...(0, Utils_js_1.getPosition)(this.options.move.center, canvasSize),
150
- radius: this.options.move.center.radius ?? 0,
152
+ radius: this.options.move.center.radius ?? defaultRadius,
151
153
  mode: this.options.move.center.mode ?? "percent",
152
154
  };
153
155
  this.direction = (0, NumberUtils_js_1.getParticleDirectionAngle)(this.options.move.direction, this.position, this.moveCenter);
@@ -172,14 +174,14 @@
172
174
  this.bubble.inRange = false;
173
175
  this.slow.inRange = false;
174
176
  const container = this.container, pathGenerator = this.pathGenerator, shapeDrawer = container.shapeDrawers.get(this.shape);
175
- shapeDrawer && shapeDrawer.particleDestroy && shapeDrawer.particleDestroy(this);
177
+ shapeDrawer?.particleDestroy?.(this);
176
178
  for (const [, plugin] of container.plugins) {
177
- plugin.particleDestroyed && plugin.particleDestroyed(this, override);
179
+ plugin.particleDestroyed?.(this, override);
178
180
  }
179
181
  for (const updater of container.particles.updaters) {
180
- updater.particleDestroyed && updater.particleDestroyed(this, override);
182
+ updater.particleDestroyed?.(this, override);
181
183
  }
182
- pathGenerator && pathGenerator.reset(this);
184
+ pathGenerator?.reset(this);
183
185
  this._engine.dispatchEvent("particleDestroyed", {
184
186
  container: this.container,
185
187
  data: {
@@ -198,7 +200,7 @@
198
200
  return this._getRollColor(this.bubble.color ?? (0, ColorUtils_js_1.getHslFromAnimation)(this.color));
199
201
  }
200
202
  getMass() {
201
- return this.getRadius() ** 2 * Math.PI * 0.5;
203
+ return this.getRadius() ** squareExp * Math.PI * half;
202
204
  }
203
205
  getPosition() {
204
206
  return {
@@ -237,14 +239,14 @@
237
239
  this.shape = (0, Utils_js_1.itemFromSingleOrMultiple)(shapeType, this.id, reduceDuplicates);
238
240
  const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
239
241
  if (overrideOptions) {
240
- if (overrideOptions.effect && overrideOptions.effect.type) {
242
+ if (overrideOptions.effect?.type) {
241
243
  const overrideEffectType = overrideOptions.effect.type, effect = (0, Utils_js_1.itemFromSingleOrMultiple)(overrideEffectType, this.id, reduceDuplicates);
242
244
  if (effect) {
243
245
  this.effect = effect;
244
246
  effectOptions.load(overrideOptions.effect);
245
247
  }
246
248
  }
247
- if (overrideOptions.shape && overrideOptions.shape.type) {
249
+ if (overrideOptions.shape?.type) {
248
250
  const overrideShapeType = overrideOptions.shape.type, shape = (0, Utils_js_1.itemFromSingleOrMultiple)(overrideShapeType, this.id, reduceDuplicates);
249
251
  if (shape) {
250
252
  this.shape = shape;
@@ -273,7 +275,7 @@
273
275
  this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
274
276
  this.options = particlesOptions;
275
277
  const pathOptions = this.options.move.path;
276
- this.pathDelay = (0, NumberUtils_js_1.getRangeValue)(pathOptions.delay.value) * 1000;
278
+ this.pathDelay = (0, NumberUtils_js_1.getRangeValue)(pathOptions.delay.value) * Constants_js_1.millisecondsToSeconds;
277
279
  if (pathOptions.generator) {
278
280
  this.pathGenerator = this._engine.getPathGenerator(pathOptions.generator);
279
281
  if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
@@ -292,7 +294,8 @@
292
294
  this._initPosition(position);
293
295
  this.initialVelocity = this._calculateVelocity();
294
296
  this.velocity = this.initialVelocity.copy();
295
- this.moveDecay = 1 - (0, NumberUtils_js_1.getRangeValue)(this.options.move.decay);
297
+ const decayOffset = 1;
298
+ this.moveDecay = decayOffset - (0, NumberUtils_js_1.getRangeValue)(this.options.move.decay);
296
299
  const particles = container.particles;
297
300
  particles.setLastZIndex(this.position.z);
298
301
  this.zIndexFactor = this.position.z / container.zLayers;
@@ -304,7 +307,7 @@
304
307
  container.effectDrawers.set(this.effect, effectDrawer);
305
308
  }
306
309
  }
307
- if (effectDrawer && effectDrawer.loadEffect) {
310
+ if (effectDrawer?.loadEffect) {
308
311
  effectDrawer.loadEffect(this);
309
312
  }
310
313
  let shapeDrawer = container.shapeDrawers.get(this.shape);
@@ -314,7 +317,7 @@
314
317
  container.shapeDrawers.set(this.shape, shapeDrawer);
315
318
  }
316
319
  }
317
- if (shapeDrawer && shapeDrawer.loadShape) {
320
+ if (shapeDrawer?.loadShape) {
318
321
  shapeDrawer.loadShape(this);
319
322
  }
320
323
  const sideCountFunc = shapeDrawer?.getSidesCount;
@@ -327,16 +330,12 @@
327
330
  updater.init(this);
328
331
  }
329
332
  for (const mover of particles.movers) {
330
- mover.init && mover.init(this);
331
- }
332
- if (effectDrawer && effectDrawer.particleInit) {
333
- effectDrawer.particleInit(container, this);
334
- }
335
- if (shapeDrawer && shapeDrawer.particleInit) {
336
- shapeDrawer.particleInit(container, this);
333
+ mover.init?.(this);
337
334
  }
335
+ effectDrawer?.particleInit?.(container, this);
336
+ shapeDrawer?.particleInit?.(container, this);
338
337
  for (const [, plugin] of container.plugins) {
339
- plugin.particleCreated && plugin.particleCreated(this);
338
+ plugin.particleCreated?.(this);
340
339
  }
341
340
  }
342
341
  isInsideCanvas() {
@@ -351,7 +350,7 @@
351
350
  }
352
351
  reset() {
353
352
  for (const updater of this.container.particles.updaters) {
354
- updater.reset && updater.reset(this);
353
+ updater.reset?.(this);
355
354
  }
356
355
  }
357
356
  }
@@ -17,7 +17,7 @@
17
17
  const QuadTree_js_1 = require("./Utils/QuadTree.js");
18
18
  const Rectangle_js_1 = require("./Utils/Rectangle.js");
19
19
  const Constants_js_1 = require("./Utils/Constants.js");
20
- const qTreeCapacity = 4;
20
+ const qTreeCapacity = 4, squareExp = 2, defaultRemoveQuantity = 1;
21
21
  const qTreeRectangle = (canvasSize) => {
22
22
  const { height, width } = canvasSize, posOffset = -0.25, sizeFactor = 1.5;
23
23
  return new Rectangle_js_1.Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
@@ -40,7 +40,7 @@
40
40
  }
41
41
  return;
42
42
  }
43
- 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);
43
+ 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);
44
44
  if (group === undefined) {
45
45
  this._limit = numberOptions.limit.value * densityFactor;
46
46
  }
@@ -55,12 +55,12 @@
55
55
  }
56
56
  };
57
57
  this._initDensityFactor = (densityOptions) => {
58
- const container = this._container;
58
+ const container = this._container, defaultFactor = 1;
59
59
  if (!container.canvas.element || !densityOptions.enable) {
60
- return 1;
60
+ return defaultFactor;
61
61
  }
62
62
  const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio;
63
- return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** 2);
63
+ return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp);
64
64
  };
65
65
  this._pushParticle = (position, overrideOptions, group, initializer) => {
66
66
  try {
@@ -91,7 +91,6 @@
91
91
  }
92
92
  catch (e) {
93
93
  (0, Utils_js_1.getLogger)().warning(`${Constants_js_1.errorPrefix} adding particle: ${e}`);
94
- return;
95
94
  }
96
95
  };
97
96
  this._removeParticle = (index, group, override) => {
@@ -99,9 +98,9 @@
99
98
  if (!particle || particle.group !== group) {
100
99
  return false;
101
100
  }
102
- const zIdx = this._zArray.indexOf(particle);
103
- this._array.splice(index, 1);
104
- this._zArray.splice(zIdx, 1);
101
+ const zIdx = this._zArray.indexOf(particle), deleteCount = 1;
102
+ this._array.splice(index, deleteCount);
103
+ this._zArray.splice(zIdx, deleteCount);
105
104
  particle.destroy(override);
106
105
  this._engine.dispatchEvent("particleRemoved", {
107
106
  container: this._container,
@@ -138,11 +137,11 @@
138
137
  }
139
138
  }
140
139
  addParticle(position, overrideOptions, group, initializer) {
141
- const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count;
142
- if (limit > 0) {
140
+ const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count, minLimit = 0;
141
+ if (limit > minLimit) {
143
142
  if (limitOptions.mode === "delete") {
144
- const countToRemove = currentCount + 1 - limit;
145
- if (countToRemove > 0) {
143
+ const countOffset = 1, minCount = 0, countToRemove = currentCount + countOffset - limit;
144
+ if (countToRemove > minCount) {
146
145
  this.removeQuantity(countToRemove);
147
146
  }
148
147
  }
@@ -233,22 +232,26 @@
233
232
  remove(particle, group, override) {
234
233
  this.removeAt(this._array.indexOf(particle), undefined, group, override);
235
234
  }
236
- removeAt(index, quantity = 1, group, override) {
237
- if (index < 0 || index > this.count) {
235
+ removeAt(index, quantity = defaultRemoveQuantity, group, override) {
236
+ const minIndex = 0;
237
+ if (index < minIndex || index > this.count) {
238
238
  return;
239
239
  }
240
240
  let deleted = 0;
241
241
  for (let i = index; deleted < quantity && i < this.count; i++) {
242
- this._removeParticle(i--, group, override) && deleted++;
242
+ if (this._removeParticle(i--, group, override)) {
243
+ deleted++;
244
+ }
243
245
  }
244
246
  }
245
247
  removeQuantity(quantity, group) {
246
- this.removeAt(0, quantity, group);
248
+ const defaultIndex = 0;
249
+ this.removeAt(defaultIndex, quantity, group);
247
250
  }
248
251
  setDensity() {
249
- const options = this._container.actualOptions, groups = options.particles.groups;
252
+ const options = this._container.actualOptions, groups = options.particles.groups, manualCount = 0;
250
253
  for (const group in groups) {
251
- this._applyDensity(groups[group], 0, group);
254
+ this._applyDensity(groups[group], manualCount, group);
252
255
  }
253
256
  this._applyDensity(options.particles, options.manualParticles.length);
254
257
  }
@@ -266,7 +269,7 @@
266
269
  pathGenerator.update();
267
270
  }
268
271
  for (const [, plugin] of container.plugins) {
269
- plugin.update && (await plugin.update(delta));
272
+ await plugin.update?.(delta);
270
273
  }
271
274
  const resizeFactor = this._resizeFactor;
272
275
  for (const particle of this._array) {
@@ -277,15 +280,17 @@
277
280
  particle.initialPosition.y *= resizeFactor.height;
278
281
  }
279
282
  particle.ignoresResizeRatio = false;
280
- await this._interactionManager.reset(particle);
283
+ this._interactionManager.reset(particle);
281
284
  for (const [, plugin] of this._container.plugins) {
282
285
  if (particle.destroyed) {
283
286
  break;
284
287
  }
285
- plugin.particleUpdate && plugin.particleUpdate(particle, delta);
288
+ plugin.particleUpdate?.(particle, delta);
286
289
  }
287
290
  for (const mover of this.movers) {
288
- mover.isEnabled(particle) && mover.move(particle, delta);
291
+ if (mover.isEnabled(particle)) {
292
+ mover.move(particle, delta);
293
+ }
289
294
  }
290
295
  if (particle.destroyed) {
291
296
  particlesToDelete.add(particle);
@@ -320,7 +325,8 @@
320
325
  if (this._needsSort) {
321
326
  const zArray = this._zArray;
322
327
  zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
323
- this._lastZIndex = zArray[zArray.length - 1].position.z;
328
+ const lengthOffset = 1;
329
+ this._lastZIndex = zArray[zArray.length - lengthOffset].position.z;
324
330
  this._needsSort = false;
325
331
  }
326
332
  }
@@ -12,16 +12,17 @@
12
12
  exports.Retina = void 0;
13
13
  const NumberUtils_js_1 = require("../Utils/NumberUtils.js");
14
14
  const Utils_js_1 = require("../Utils/Utils.js");
15
+ const defaultRatio = 1, defaultReduceFactor = 1;
15
16
  class Retina {
16
17
  constructor(container) {
17
18
  this.container = container;
18
- this.pixelRatio = 1;
19
- this.reduceFactor = 1;
19
+ this.pixelRatio = defaultRatio;
20
+ this.reduceFactor = defaultReduceFactor;
20
21
  }
21
22
  init() {
22
23
  const container = this.container, options = container.actualOptions;
23
- this.pixelRatio = !options.detectRetina || (0, Utils_js_1.isSsr)() ? 1 : window.devicePixelRatio;
24
- this.reduceFactor = 1;
24
+ this.pixelRatio = !options.detectRetina || (0, Utils_js_1.isSsr)() ? defaultRatio : window.devicePixelRatio;
25
+ this.reduceFactor = defaultReduceFactor;
25
26
  const ratio = this.pixelRatio, canvas = container.canvas;
26
27
  if (canvas.element) {
27
28
  const element = canvas.element;
@@ -13,6 +13,7 @@
13
13
  const Range_js_1 = require("./Range.js");
14
14
  const Rectangle_js_1 = require("./Rectangle.js");
15
15
  const NumberUtils_js_1 = require("../../Utils/NumberUtils.js");
16
+ const squareExp = 2;
16
17
  class Circle extends Range_js_1.Range {
17
18
  constructor(x, y, radius) {
18
19
  super(x, y);
@@ -24,12 +25,12 @@
24
25
  intersects(range) {
25
26
  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;
26
27
  if (range instanceof Circle) {
27
- const rSum = r + range.radius, dist = Math.sqrt(distPos.x ** 2 + distPos.y ** 2);
28
+ const rSum = r + range.radius, dist = Math.sqrt(distPos.x ** squareExp + distPos.y ** squareExp);
28
29
  return rSum > dist;
29
30
  }
30
31
  else if (range instanceof Rectangle_js_1.Rectangle) {
31
- const { width, height } = range.size, edges = Math.pow(distPos.x - width, 2) + Math.pow(distPos.y - height, 2);
32
- return (edges <= r ** 2 ||
32
+ const { width, height } = range.size, edges = Math.pow(distPos.x - width, squareExp) + Math.pow(distPos.y - height, squareExp);
33
+ return (edges <= r ** squareExp ||
33
34
  (distPos.x <= r + width && distPos.y <= r + height) ||
34
35
  distPos.x <= width ||
35
36
  distPos.y <= height);
@@ -9,7 +9,7 @@
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- 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;
12
+ 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;
13
13
  exports.generatedAttribute = "generated";
14
14
  exports.mouseDownEvent = "pointerdown";
15
15
  exports.mouseUpEvent = "pointerup";
@@ -23,4 +23,7 @@
23
23
  exports.resizeEvent = "resize";
24
24
  exports.visibilityChangeEvent = "visibilitychange";
25
25
  exports.errorPrefix = "tsParticles - Error";
26
+ exports.percentDenominator = 100;
27
+ exports.halfRandom = 0.5;
28
+ exports.millisecondsToSeconds = 1000;
26
29
  });
@@ -12,6 +12,7 @@
12
12
  exports.EventListeners = void 0;
13
13
  const Utils_js_1 = require("../../Utils/Utils.js");
14
14
  const Constants_js_1 = require("./Constants.js");
15
+ const double = 2;
15
16
  function manageListener(element, event, handler, add, options) {
16
17
  if (add) {
17
18
  let addOptions = { passive: true };
@@ -44,13 +45,14 @@
44
45
  (0, Utils_js_1.executeOnSingleOrMultiple)(onClick.mode, (mode) => this.container.handleClickMode(mode));
45
46
  }
46
47
  if (e.type === "touchend") {
47
- setTimeout(() => this._mouseTouchFinish(), 500);
48
+ const touchDelay = 500;
49
+ setTimeout(() => this._mouseTouchFinish(), touchDelay);
48
50
  }
49
51
  };
50
52
  this._handleThemeChange = (e) => {
51
53
  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);
52
54
  if (theme && theme.default.auto) {
53
- container.loadTheme(themeName);
55
+ void container.loadTheme(themeName);
54
56
  }
55
57
  };
56
58
  this._handleVisibilityChange = () => {
@@ -73,15 +75,16 @@
73
75
  }
74
76
  }
75
77
  };
76
- this._handleWindowResize = async () => {
78
+ this._handleWindowResize = () => {
77
79
  if (this._resizeTimeout) {
78
80
  clearTimeout(this._resizeTimeout);
79
81
  delete this._resizeTimeout;
80
82
  }
81
- this._resizeTimeout = setTimeout(async () => {
83
+ const handleResize = async () => {
82
84
  const canvas = this.container.canvas;
83
- canvas && (await canvas.windowResize());
84
- }, this.container.actualOptions.interactivity.events.resize.delay * 1000);
85
+ await canvas?.windowResize();
86
+ };
87
+ this._resizeTimeout = setTimeout(() => void handleResize(), this.container.actualOptions.interactivity.events.resize.delay * Constants_js_1.millisecondsToSeconds);
85
88
  };
86
89
  this._manageInteractivityListeners = (mouseLeaveTmpEvent, add) => {
87
90
  const handlers = this._handlers, container = this.container, options = container.actualOptions;
@@ -167,12 +170,12 @@
167
170
  delete this._resizeObserver;
168
171
  }
169
172
  else if (!this._resizeObserver && add && canvasEl) {
170
- this._resizeObserver = new ResizeObserver(async (entries) => {
173
+ this._resizeObserver = new ResizeObserver((entries) => {
171
174
  const entry = entries.find((e) => e.target === canvasEl);
172
175
  if (!entry) {
173
176
  return;
174
177
  }
175
- await this._handleWindowResize();
178
+ this._handleWindowResize();
176
179
  });
177
180
  this._resizeObserver.observe(canvasEl);
178
181
  }
@@ -223,7 +226,7 @@
223
226
  };
224
227
  this._mouseTouchMove = (e) => {
225
228
  const container = this.container, options = container.actualOptions, interactivity = container.interactivity, canvasEl = container.canvas.element;
226
- if (!interactivity || !interactivity.element) {
229
+ if (!interactivity?.element) {
227
230
  return;
228
231
  }
229
232
  interactivity.mouse.inside = true;
@@ -245,8 +248,8 @@
245
248
  if (source && target && canvasEl) {
246
249
  const sourceRect = source.getBoundingClientRect(), targetRect = target.getBoundingClientRect(), canvasRect = canvasEl.getBoundingClientRect();
247
250
  pos = {
248
- x: mouseEvent.offsetX + 2 * sourceRect.left - (targetRect.left + canvasRect.left),
249
- y: mouseEvent.offsetY + 2 * sourceRect.top - (targetRect.top + canvasRect.top),
251
+ x: mouseEvent.offsetX + double * sourceRect.left - (targetRect.left + canvasRect.left),
252
+ y: mouseEvent.offsetY + double * sourceRect.top - (targetRect.top + canvasRect.top),
250
253
  };
251
254
  }
252
255
  else {
@@ -266,10 +269,10 @@
266
269
  else {
267
270
  this._canPush = e.type !== "touchmove";
268
271
  if (canvasEl) {
269
- const touchEvent = e, lastTouch = touchEvent.touches[touchEvent.touches.length - 1], canvasRect = canvasEl.getBoundingClientRect();
272
+ const touchEvent = e, lengthOffset = 1, lastTouch = touchEvent.touches[touchEvent.touches.length - lengthOffset], canvasRect = canvasEl.getBoundingClientRect(), defaultCoordinate = 0;
270
273
  pos = {
271
- x: lastTouch.clientX - (canvasRect.left ?? 0),
272
- y: lastTouch.clientY - (canvasRect.top ?? 0),
274
+ x: lastTouch.clientX - (canvasRect.left ?? defaultCoordinate),
275
+ y: lastTouch.clientY - (canvasRect.top ?? defaultCoordinate),
273
276
  };
274
277
  }
275
278
  }
@@ -12,8 +12,8 @@
12
12
  exports.ExternalInteractorBase = void 0;
13
13
  class ExternalInteractorBase {
14
14
  constructor(container) {
15
- this.container = container;
16
15
  this.type = "external";
16
+ this.container = container;
17
17
  }
18
18
  }
19
19
  exports.ExternalInteractorBase = ExternalInteractorBase;
@@ -20,12 +20,14 @@
20
20
  }
21
21
  async externalInteract(delta) {
22
22
  for (const interactor of this._externalInteractors) {
23
- interactor.isEnabled() && (await interactor.interact(delta));
23
+ if (interactor.isEnabled()) {
24
+ await interactor.interact(delta);
25
+ }
24
26
  }
25
27
  }
26
28
  handleClickMode(mode) {
27
29
  for (const interactor of this._externalInteractors) {
28
- interactor.handleClickMode && interactor.handleClickMode(mode);
30
+ interactor.handleClickMode?.(mode);
29
31
  }
30
32
  }
31
33
  init() {
@@ -48,15 +50,21 @@
48
50
  interactor.clear(particle, delta);
49
51
  }
50
52
  for (const interactor of this._particleInteractors) {
51
- interactor.isEnabled(particle) && (await interactor.interact(particle, delta));
53
+ if (interactor.isEnabled(particle)) {
54
+ await interactor.interact(particle, delta);
55
+ }
52
56
  }
53
57
  }
54
- async reset(particle) {
58
+ reset(particle) {
55
59
  for (const interactor of this._externalInteractors) {
56
- interactor.isEnabled() && interactor.reset(particle);
60
+ if (interactor.isEnabled()) {
61
+ interactor.reset(particle);
62
+ }
57
63
  }
58
64
  for (const interactor of this._particleInteractors) {
59
- interactor.isEnabled(particle) && interactor.reset(particle);
65
+ if (interactor.isEnabled(particle)) {
66
+ interactor.reset(particle);
67
+ }
60
68
  }
61
69
  }
62
70
  }
@@ -12,8 +12,8 @@
12
12
  exports.ParticlesInteractorBase = void 0;
13
13
  class ParticlesInteractorBase {
14
14
  constructor(container) {
15
- this.container = container;
16
15
  this.type = "particles";
16
+ this.container = container;
17
17
  }
18
18
  }
19
19
  exports.ParticlesInteractorBase = ParticlesInteractorBase;
@@ -13,14 +13,16 @@
13
13
  const Circle_js_1 = require("./Circle.js");
14
14
  const Rectangle_js_1 = require("./Rectangle.js");
15
15
  const NumberUtils_js_1 = require("../../Utils/NumberUtils.js");
16
+ const half = 0.5, double = 2, subdivideCount = 4;
16
17
  class QuadTree {
17
18
  constructor(rectangle, capacity) {
18
19
  this.rectangle = rectangle;
19
20
  this.capacity = capacity;
20
21
  this._subdivide = () => {
21
22
  const { x, y } = this.rectangle.position, { width, height } = this.rectangle.size, { capacity } = this;
22
- for (let i = 0; i < 4; i++) {
23
- 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));
23
+ for (let i = 0; i < subdivideCount; i++) {
24
+ const fixedIndex = i % double;
25
+ 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));
24
26
  }
25
27
  this._divided = true;
26
28
  };
@@ -42,7 +44,7 @@
42
44
  return this._subs.some((sub) => sub.insert(point));
43
45
  }
44
46
  query(range, check, found) {
45
- const res = found || [];
47
+ const res = found ?? [];
46
48
  if (!range.intersects(this.rectangle)) {
47
49
  return [];
48
50
  }
@@ -11,12 +11,17 @@
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Vector = void 0;
13
13
  const Vector3d_js_1 = require("./Vector3d.js");
14
+ const origin = {
15
+ x: 0,
16
+ y: 0,
17
+ z: 0,
18
+ };
14
19
  class Vector extends Vector3d_js_1.Vector3d {
15
20
  constructor(xOrCoords, y) {
16
- super(xOrCoords, y, 0);
21
+ super(xOrCoords, y, origin.z);
17
22
  }
18
23
  static get origin() {
19
- return Vector.create(0, 0);
24
+ return Vector.create(origin.x, origin.y);
20
25
  }
21
26
  static clone(source) {
22
27
  return Vector.create(source.x, source.y);