@tsparticles/engine 3.3.0 → 3.5.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 (272) hide show
  1. package/README.md +0 -4
  2. package/browser/Core/Canvas.js +27 -22
  3. package/browser/Core/Container.js +57 -44
  4. package/browser/Core/Engine.js +82 -74
  5. package/browser/Core/Particle.js +29 -15
  6. package/browser/Core/Particles.js +23 -24
  7. package/browser/Core/Utils/EventListeners.js +18 -17
  8. package/browser/Core/Utils/ExternalInteractorBase.js +2 -1
  9. package/browser/Core/Utils/InteractionManager.js +3 -2
  10. package/browser/Core/Utils/ParticlesInteractorBase.js +2 -1
  11. package/browser/Core/Utils/QuadTree.js +1 -1
  12. package/browser/Core/Utils/Ranges.js +5 -4
  13. package/browser/Enums/AnimationStatus.js +5 -1
  14. package/browser/Enums/Directions/MoveDirection.js +14 -1
  15. package/browser/Enums/Directions/OutModeDirection.js +7 -1
  16. package/browser/Enums/Directions/RotateDirection.js +6 -1
  17. package/browser/Enums/InteractivityDetect.js +6 -1
  18. package/browser/Enums/Modes/AnimationMode.js +7 -1
  19. package/browser/Enums/Modes/CollisionMode.js +6 -1
  20. package/browser/Enums/Modes/LimitMode.js +5 -1
  21. package/browser/Enums/Modes/OutMode.js +8 -1
  22. package/browser/Enums/Modes/PixelMode.js +5 -1
  23. package/browser/Enums/Modes/ResponsiveMode.js +5 -1
  24. package/browser/Enums/Modes/ThemeMode.js +6 -1
  25. package/browser/Enums/Types/AlterType.js +5 -1
  26. package/browser/Enums/Types/DestroyType.js +6 -1
  27. package/browser/Enums/Types/DivType.js +5 -1
  28. package/browser/Enums/Types/EasingType.js +30 -1
  29. package/browser/Enums/Types/EventType.js +15 -1
  30. package/browser/Enums/Types/GradientType.js +6 -1
  31. package/browser/Enums/Types/InteractorType.js +5 -1
  32. package/browser/Enums/Types/ParticleOutType.js +6 -1
  33. package/browser/Enums/Types/StartValueType.js +6 -1
  34. package/browser/Options/Classes/AnimationOptions.js +4 -2
  35. package/browser/Options/Classes/Interactivity/Events/DivEvent.js +2 -1
  36. package/browser/Options/Classes/Interactivity/Events/Events.js +1 -1
  37. package/browser/Options/Classes/Interactivity/Interactivity.js +2 -1
  38. package/browser/Options/Classes/ManualParticle.js +2 -1
  39. package/browser/Options/Classes/Options.js +14 -12
  40. package/browser/Options/Classes/Particles/Collisions/Collisions.js +2 -1
  41. package/browser/Options/Classes/Particles/Move/Move.js +2 -1
  42. package/browser/Options/Classes/Particles/Move/MoveCenter.js +2 -1
  43. package/browser/Options/Classes/Particles/Move/OutModes.js +2 -1
  44. package/browser/Options/Classes/Particles/Number/ParticlesNumberLimit.js +2 -1
  45. package/browser/Options/Classes/Particles/Opacity/OpacityAnimation.js +2 -1
  46. package/browser/Options/Classes/Particles/ParticlesOptions.js +1 -1
  47. package/browser/Options/Classes/Particles/Size/SizeAnimation.js +2 -1
  48. package/browser/Options/Classes/Responsive.js +5 -4
  49. package/browser/Options/Classes/Theme/ThemeDefault.js +2 -1
  50. package/browser/Types/RangeType.js +5 -1
  51. package/browser/Utils/CanvasUtils.js +13 -7
  52. package/browser/Utils/ColorUtils.js +17 -9
  53. package/browser/Utils/EventDispatcher.js +1 -1
  54. package/browser/Utils/HslColorManager.js +11 -4
  55. package/browser/Utils/NumberUtils.js +28 -14
  56. package/browser/Utils/RgbColorManager.js +11 -4
  57. package/browser/Utils/Utils.js +37 -31
  58. package/cjs/Core/Canvas.js +27 -22
  59. package/cjs/Core/Container.js +57 -44
  60. package/cjs/Core/Engine.js +82 -74
  61. package/cjs/Core/Particle.js +29 -15
  62. package/cjs/Core/Particles.js +23 -24
  63. package/cjs/Core/Utils/EventListeners.js +18 -17
  64. package/cjs/Core/Utils/ExternalInteractorBase.js +2 -1
  65. package/cjs/Core/Utils/InteractionManager.js +3 -2
  66. package/cjs/Core/Utils/ParticlesInteractorBase.js +2 -1
  67. package/cjs/Core/Utils/QuadTree.js +1 -1
  68. package/cjs/Core/Utils/Ranges.js +5 -4
  69. package/cjs/Enums/AnimationStatus.js +6 -0
  70. package/cjs/Enums/Directions/MoveDirection.js +15 -0
  71. package/cjs/Enums/Directions/OutModeDirection.js +8 -0
  72. package/cjs/Enums/Directions/RotateDirection.js +7 -0
  73. package/cjs/Enums/InteractivityDetect.js +7 -0
  74. package/cjs/Enums/Modes/AnimationMode.js +8 -0
  75. package/cjs/Enums/Modes/CollisionMode.js +7 -0
  76. package/cjs/Enums/Modes/LimitMode.js +6 -0
  77. package/cjs/Enums/Modes/OutMode.js +9 -0
  78. package/cjs/Enums/Modes/PixelMode.js +6 -0
  79. package/cjs/Enums/Modes/ResponsiveMode.js +6 -0
  80. package/cjs/Enums/Modes/ThemeMode.js +7 -0
  81. package/cjs/Enums/Types/AlterType.js +6 -0
  82. package/cjs/Enums/Types/DestroyType.js +7 -0
  83. package/cjs/Enums/Types/DivType.js +6 -0
  84. package/cjs/Enums/Types/EasingType.js +31 -0
  85. package/cjs/Enums/Types/EventType.js +16 -0
  86. package/cjs/Enums/Types/GradientType.js +7 -0
  87. package/cjs/Enums/Types/InteractorType.js +6 -0
  88. package/cjs/Enums/Types/ParticleOutType.js +7 -0
  89. package/cjs/Enums/Types/StartValueType.js +7 -0
  90. package/cjs/Options/Classes/AnimationOptions.js +4 -2
  91. package/cjs/Options/Classes/Interactivity/Events/DivEvent.js +2 -1
  92. package/cjs/Options/Classes/Interactivity/Events/Events.js +1 -1
  93. package/cjs/Options/Classes/Interactivity/Interactivity.js +2 -1
  94. package/cjs/Options/Classes/ManualParticle.js +2 -1
  95. package/cjs/Options/Classes/Options.js +14 -12
  96. package/cjs/Options/Classes/Particles/Collisions/Collisions.js +2 -1
  97. package/cjs/Options/Classes/Particles/Move/Move.js +2 -1
  98. package/cjs/Options/Classes/Particles/Move/MoveCenter.js +2 -1
  99. package/cjs/Options/Classes/Particles/Move/OutModes.js +2 -1
  100. package/cjs/Options/Classes/Particles/Number/ParticlesNumberLimit.js +2 -1
  101. package/cjs/Options/Classes/Particles/Opacity/OpacityAnimation.js +2 -1
  102. package/cjs/Options/Classes/Particles/ParticlesOptions.js +1 -1
  103. package/cjs/Options/Classes/Particles/Size/SizeAnimation.js +2 -1
  104. package/cjs/Options/Classes/Responsive.js +5 -4
  105. package/cjs/Options/Classes/Theme/ThemeDefault.js +2 -1
  106. package/cjs/Types/RangeType.js +6 -0
  107. package/cjs/Utils/CanvasUtils.js +24 -19
  108. package/cjs/Utils/ColorUtils.js +37 -30
  109. package/cjs/Utils/EventDispatcher.js +1 -1
  110. package/cjs/Utils/HslColorManager.js +11 -4
  111. package/cjs/Utils/NumberUtils.js +54 -38
  112. package/cjs/Utils/OptionsUtils.js +2 -3
  113. package/cjs/Utils/RgbColorManager.js +11 -4
  114. package/cjs/Utils/TypeUtils.js +6 -7
  115. package/cjs/Utils/Utils.js +66 -61
  116. package/cjs/init.js +1 -2
  117. package/esm/Core/Canvas.js +27 -22
  118. package/esm/Core/Container.js +57 -44
  119. package/esm/Core/Engine.js +82 -74
  120. package/esm/Core/Particle.js +29 -15
  121. package/esm/Core/Particles.js +23 -24
  122. package/esm/Core/Utils/EventListeners.js +18 -17
  123. package/esm/Core/Utils/ExternalInteractorBase.js +2 -1
  124. package/esm/Core/Utils/InteractionManager.js +3 -2
  125. package/esm/Core/Utils/ParticlesInteractorBase.js +2 -1
  126. package/esm/Core/Utils/QuadTree.js +1 -1
  127. package/esm/Core/Utils/Ranges.js +5 -4
  128. package/esm/Enums/AnimationStatus.js +5 -1
  129. package/esm/Enums/Directions/MoveDirection.js +14 -1
  130. package/esm/Enums/Directions/OutModeDirection.js +7 -1
  131. package/esm/Enums/Directions/RotateDirection.js +6 -1
  132. package/esm/Enums/InteractivityDetect.js +6 -1
  133. package/esm/Enums/Modes/AnimationMode.js +7 -1
  134. package/esm/Enums/Modes/CollisionMode.js +6 -1
  135. package/esm/Enums/Modes/LimitMode.js +5 -1
  136. package/esm/Enums/Modes/OutMode.js +8 -1
  137. package/esm/Enums/Modes/PixelMode.js +5 -1
  138. package/esm/Enums/Modes/ResponsiveMode.js +5 -1
  139. package/esm/Enums/Modes/ThemeMode.js +6 -1
  140. package/esm/Enums/Types/AlterType.js +5 -1
  141. package/esm/Enums/Types/DestroyType.js +6 -1
  142. package/esm/Enums/Types/DivType.js +5 -1
  143. package/esm/Enums/Types/EasingType.js +30 -1
  144. package/esm/Enums/Types/EventType.js +15 -1
  145. package/esm/Enums/Types/GradientType.js +6 -1
  146. package/esm/Enums/Types/InteractorType.js +5 -1
  147. package/esm/Enums/Types/ParticleOutType.js +6 -1
  148. package/esm/Enums/Types/StartValueType.js +6 -1
  149. package/esm/Options/Classes/AnimationOptions.js +4 -2
  150. package/esm/Options/Classes/Interactivity/Events/DivEvent.js +2 -1
  151. package/esm/Options/Classes/Interactivity/Events/Events.js +1 -1
  152. package/esm/Options/Classes/Interactivity/Interactivity.js +2 -1
  153. package/esm/Options/Classes/ManualParticle.js +2 -1
  154. package/esm/Options/Classes/Options.js +14 -12
  155. package/esm/Options/Classes/Particles/Collisions/Collisions.js +2 -1
  156. package/esm/Options/Classes/Particles/Move/Move.js +2 -1
  157. package/esm/Options/Classes/Particles/Move/MoveCenter.js +2 -1
  158. package/esm/Options/Classes/Particles/Move/OutModes.js +2 -1
  159. package/esm/Options/Classes/Particles/Number/ParticlesNumberLimit.js +2 -1
  160. package/esm/Options/Classes/Particles/Opacity/OpacityAnimation.js +2 -1
  161. package/esm/Options/Classes/Particles/ParticlesOptions.js +1 -1
  162. package/esm/Options/Classes/Particles/Size/SizeAnimation.js +2 -1
  163. package/esm/Options/Classes/Responsive.js +5 -4
  164. package/esm/Options/Classes/Theme/ThemeDefault.js +2 -1
  165. package/esm/Types/RangeType.js +5 -1
  166. package/esm/Utils/CanvasUtils.js +13 -7
  167. package/esm/Utils/ColorUtils.js +17 -9
  168. package/esm/Utils/EventDispatcher.js +1 -1
  169. package/esm/Utils/HslColorManager.js +11 -4
  170. package/esm/Utils/NumberUtils.js +28 -14
  171. package/esm/Utils/RgbColorManager.js +11 -4
  172. package/esm/Utils/Utils.js +37 -31
  173. package/package.json +1 -1
  174. package/report.html +1 -1
  175. package/tsparticles.engine.js +327 -225
  176. package/tsparticles.engine.min.js +1 -1
  177. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  178. package/types/Core/Container.d.ts +4 -2
  179. package/types/Core/Engine.d.ts +6 -5
  180. package/types/Core/Interfaces/IPlugin.d.ts +3 -4
  181. package/types/Core/Interfaces/IShapeDrawer.d.ts +1 -0
  182. package/types/Core/Particle.d.ts +1 -0
  183. package/types/Enums/AnimationStatus.d.ts +1 -1
  184. package/types/Enums/Directions/MoveDirection.d.ts +1 -1
  185. package/types/Enums/Directions/OutModeDirection.d.ts +1 -1
  186. package/types/Enums/Directions/RotateDirection.d.ts +1 -1
  187. package/types/Enums/InteractivityDetect.d.ts +1 -1
  188. package/types/Enums/Modes/AnimationMode.d.ts +1 -1
  189. package/types/Enums/Modes/CollisionMode.d.ts +1 -1
  190. package/types/Enums/Modes/LimitMode.d.ts +1 -1
  191. package/types/Enums/Modes/OutMode.d.ts +1 -1
  192. package/types/Enums/Modes/PixelMode.d.ts +1 -1
  193. package/types/Enums/Modes/ResponsiveMode.d.ts +1 -1
  194. package/types/Enums/Modes/ThemeMode.d.ts +1 -1
  195. package/types/Enums/Types/AlterType.d.ts +1 -1
  196. package/types/Enums/Types/DestroyType.d.ts +1 -1
  197. package/types/Enums/Types/DivType.d.ts +1 -1
  198. package/types/Enums/Types/EasingType.d.ts +1 -1
  199. package/types/Enums/Types/EventType.d.ts +1 -1
  200. package/types/Enums/Types/GradientType.d.ts +1 -1
  201. package/types/Enums/Types/InteractorType.d.ts +1 -1
  202. package/types/Enums/Types/ParticleOutType.d.ts +1 -1
  203. package/types/Enums/Types/StartValueType.d.ts +1 -1
  204. package/types/Options/Classes/Options.d.ts +2 -1
  205. package/types/Options/Classes/Responsive.d.ts +2 -2
  206. package/types/Options/Classes/Theme/Theme.d.ts +2 -2
  207. package/types/Options/Interfaces/IResponsive.d.ts +2 -3
  208. package/types/Options/Interfaces/Theme/ITheme.d.ts +2 -3
  209. package/types/Types/RangeType.d.ts +1 -1
  210. package/types/Utils/NumberUtils.d.ts +3 -0
  211. package/umd/Core/Canvas.js +27 -22
  212. package/umd/Core/Container.js +58 -45
  213. package/umd/Core/Engine.js +83 -99
  214. package/umd/Core/Particle.js +30 -16
  215. package/umd/Core/Particles.js +24 -25
  216. package/umd/Core/Utils/EventListeners.js +19 -18
  217. package/umd/Core/Utils/ExternalInteractorBase.js +3 -2
  218. package/umd/Core/Utils/InteractionManager.js +4 -3
  219. package/umd/Core/Utils/ParticlesInteractorBase.js +3 -2
  220. package/umd/Core/Utils/QuadTree.js +1 -1
  221. package/umd/Core/Utils/Ranges.js +6 -5
  222. package/umd/Enums/AnimationStatus.js +6 -0
  223. package/umd/Enums/Directions/MoveDirection.js +15 -0
  224. package/umd/Enums/Directions/OutModeDirection.js +8 -0
  225. package/umd/Enums/Directions/RotateDirection.js +7 -0
  226. package/umd/Enums/InteractivityDetect.js +7 -0
  227. package/umd/Enums/Modes/AnimationMode.js +8 -0
  228. package/umd/Enums/Modes/CollisionMode.js +7 -0
  229. package/umd/Enums/Modes/LimitMode.js +6 -0
  230. package/umd/Enums/Modes/OutMode.js +9 -0
  231. package/umd/Enums/Modes/PixelMode.js +6 -0
  232. package/umd/Enums/Modes/ResponsiveMode.js +6 -0
  233. package/umd/Enums/Modes/ThemeMode.js +7 -0
  234. package/umd/Enums/Types/AlterType.js +6 -0
  235. package/umd/Enums/Types/DestroyType.js +7 -0
  236. package/umd/Enums/Types/DivType.js +6 -0
  237. package/umd/Enums/Types/EasingType.js +31 -0
  238. package/umd/Enums/Types/EventType.js +16 -0
  239. package/umd/Enums/Types/GradientType.js +7 -0
  240. package/umd/Enums/Types/InteractorType.js +6 -0
  241. package/umd/Enums/Types/ParticleOutType.js +7 -0
  242. package/umd/Enums/Types/StartValueType.js +7 -0
  243. package/umd/Options/Classes/AnimationOptions.js +5 -3
  244. package/umd/Options/Classes/Interactivity/Events/DivEvent.js +3 -2
  245. package/umd/Options/Classes/Interactivity/Events/Events.js +1 -1
  246. package/umd/Options/Classes/Interactivity/Interactivity.js +3 -2
  247. package/umd/Options/Classes/ManualParticle.js +3 -2
  248. package/umd/Options/Classes/Options.js +15 -13
  249. package/umd/Options/Classes/Particles/Collisions/Collisions.js +3 -2
  250. package/umd/Options/Classes/Particles/Move/Move.js +3 -2
  251. package/umd/Options/Classes/Particles/Move/MoveCenter.js +3 -2
  252. package/umd/Options/Classes/Particles/Move/OutModes.js +3 -2
  253. package/umd/Options/Classes/Particles/Number/ParticlesNumberLimit.js +3 -2
  254. package/umd/Options/Classes/Particles/Opacity/OpacityAnimation.js +3 -2
  255. package/umd/Options/Classes/Particles/ParticlesOptions.js +1 -1
  256. package/umd/Options/Classes/Particles/Size/SizeAnimation.js +3 -2
  257. package/umd/Options/Classes/Responsive.js +6 -5
  258. package/umd/Options/Classes/Theme/ThemeDefault.js +3 -2
  259. package/umd/Types/RangeType.js +6 -0
  260. package/umd/Utils/CanvasUtils.js +25 -20
  261. package/umd/Utils/ColorUtils.js +38 -31
  262. package/umd/Utils/EventDispatcher.js +1 -1
  263. package/umd/Utils/HslColorManager.js +11 -4
  264. package/umd/Utils/NumberUtils.js +55 -39
  265. package/umd/Utils/OptionsUtils.js +2 -3
  266. package/umd/Utils/RgbColorManager.js +11 -4
  267. package/umd/Utils/TypeUtils.js +6 -7
  268. package/umd/Utils/Utils.js +67 -62
  269. package/umd/init.js +1 -2
  270. package/174.min.js +0 -2
  271. package/174.min.js.LICENSE.txt +0 -1
  272. package/dist_browser_Core_Container_js.js +0 -102
@@ -1,11 +1,12 @@
1
+ import { animate, cancelAnimation, getRangeValue } from "../Utils/NumberUtils.js";
1
2
  import { errorPrefix, millisecondsToSeconds } from "./Utils/Constants.js";
2
3
  import { getLogger, safeIntersectionObserver } from "../Utils/Utils.js";
3
4
  import { Canvas } from "./Canvas.js";
4
5
  import { EventListeners } from "./Utils/EventListeners.js";
6
+ import { EventType } from "../Enums/Types/EventType.js";
5
7
  import { Options } from "../Options/Classes/Options.js";
6
8
  import { Particles } from "./Particles.js";
7
9
  import { Retina } from "./Retina.js";
8
- import { getRangeValue } from "../Utils/NumberUtils.js";
9
10
  import { loadOptions } from "../Utils/OptionsUtils.js";
10
11
  function guardCheck(container) {
11
12
  return container && !container.destroyed;
@@ -24,7 +25,7 @@ function loadContainerOptions(engine, container, ...sourceOptionsArr) {
24
25
  }
25
26
  export class Container {
26
27
  constructor(engine, id, sourceOptions) {
27
- this._intersectionManager = (entries) => {
28
+ this._intersectionManager = entries => {
28
29
  if (!guardCheck(this) || !this.actualOptions.pauseOnOutsideViewport) {
29
30
  return;
30
31
  }
@@ -83,6 +84,7 @@ export class Container {
83
84
  this._lastFrameTime = 0;
84
85
  this.zLayers = 100;
85
86
  this.pageHidden = false;
87
+ this._clickHandlers = new Map();
86
88
  this._sourceOptions = sourceOptions;
87
89
  this._initialSourceOptions = sourceOptions;
88
90
  this.retina = new Retina(this);
@@ -101,8 +103,8 @@ export class Container {
101
103
  this._options = loadContainerOptions(this._engine, this);
102
104
  this.actualOptions = loadContainerOptions(this._engine, this);
103
105
  this._eventListeners = new EventListeners(this);
104
- this._intersectionObserver = safeIntersectionObserver((entries) => this._intersectionManager(entries));
105
- this._engine.dispatchEvent("containerBuilt", { container: this });
106
+ this._intersectionObserver = safeIntersectionObserver(entries => this._intersectionManager(entries));
107
+ this._engine.dispatchEvent(EventType.containerBuilt, { container: this });
106
108
  }
107
109
  get animationStatus() {
108
110
  return !this._paused && !this.pageHidden && guardCheck(this);
@@ -130,8 +132,7 @@ export class Container {
130
132
  y: pos.y * pxRatio,
131
133
  }, particles = this.particles.quadTree.queryCircle(posRetina, radius * pxRatio);
132
134
  callback(e, particles);
133
- };
134
- const clickHandler = (e) => {
135
+ }, clickHandler = (e) => {
135
136
  if (!guardCheck(this)) {
136
137
  return;
137
138
  }
@@ -140,27 +141,23 @@ export class Container {
140
141
  y: mouseEvent.offsetY || mouseEvent.clientY,
141
142
  }, radius = 1;
142
143
  clickOrTouchHandler(e, pos, radius);
143
- };
144
- const touchStartHandler = () => {
144
+ }, touchStartHandler = () => {
145
145
  if (!guardCheck(this)) {
146
146
  return;
147
147
  }
148
148
  touched = true;
149
149
  touchMoved = false;
150
- };
151
- const touchMoveHandler = () => {
150
+ }, touchMoveHandler = () => {
152
151
  if (!guardCheck(this)) {
153
152
  return;
154
153
  }
155
154
  touchMoved = true;
156
- };
157
- const touchEndHandler = (e) => {
155
+ }, touchEndHandler = (e) => {
158
156
  if (!guardCheck(this)) {
159
157
  return;
160
158
  }
161
159
  if (touched && !touchMoved) {
162
- const touchEvent = e;
163
- const lengthOffset = 1;
160
+ const touchEvent = e, lengthOffset = 1;
164
161
  let lastTouch = touchEvent.touches[touchEvent.touches.length - lengthOffset];
165
162
  if (!lastTouch) {
166
163
  lastTouch = touchEvent.changedTouches[touchEvent.changedTouches.length - lengthOffset];
@@ -176,8 +173,7 @@ export class Container {
176
173
  }
177
174
  touched = false;
178
175
  touchMoved = false;
179
- };
180
- const touchCancelHandler = () => {
176
+ }, touchCancelHandler = () => {
181
177
  if (!guardCheck(this)) {
182
178
  return;
183
179
  }
@@ -185,11 +181,14 @@ export class Container {
185
181
  touchMoved = false;
186
182
  };
187
183
  let touched = false, touchMoved = false;
188
- el.addEventListener("click", clickHandler);
189
- el.addEventListener("touchstart", touchStartHandler);
190
- el.addEventListener("touchmove", touchMoveHandler);
191
- el.addEventListener("touchend", touchEndHandler);
192
- el.addEventListener("touchcancel", touchCancelHandler);
184
+ this._clickHandlers.set("click", clickHandler);
185
+ this._clickHandlers.set("touchstart", touchStartHandler);
186
+ this._clickHandlers.set("touchmove", touchMoveHandler);
187
+ this._clickHandlers.set("touchend", touchEndHandler);
188
+ this._clickHandlers.set("touchcancel", touchCancelHandler);
189
+ for (const [key, handler] of this._clickHandlers) {
190
+ el.addEventListener(key, handler);
191
+ }
193
192
  }
194
193
  addLifeTime(value) {
195
194
  this._lifeTime += value;
@@ -204,11 +203,21 @@ export class Container {
204
203
  alive() {
205
204
  return !this._duration || this._lifeTime <= this._duration;
206
205
  }
207
- destroy() {
206
+ clearClickHandlers() {
207
+ if (!guardCheck(this)) {
208
+ return;
209
+ }
210
+ for (const [key, handler] of this._clickHandlers) {
211
+ this.interactivity.element?.removeEventListener(key, handler);
212
+ }
213
+ this._clickHandlers.clear();
214
+ }
215
+ destroy(remove = true) {
208
216
  if (!guardCheck(this)) {
209
217
  return;
210
218
  }
211
219
  this.stop();
220
+ this.clearClickHandlers();
212
221
  this.particles.destroy();
213
222
  this.canvas.destroy();
214
223
  for (const [, effectDrawer] of this.effectDrawers) {
@@ -225,12 +234,14 @@ export class Container {
225
234
  }
226
235
  this._engine.clearPlugins(this);
227
236
  this.destroyed = true;
228
- const mainArr = this._engine.dom(), idx = mainArr.findIndex((t) => t === this), minIndex = 0;
229
- if (idx >= minIndex) {
230
- const deleteCount = 1;
231
- mainArr.splice(idx, deleteCount);
237
+ if (remove) {
238
+ const mainArr = this._engine.items, idx = mainArr.findIndex(t => t === this), minIndex = 0;
239
+ if (idx >= minIndex) {
240
+ const deleteCount = 1;
241
+ mainArr.splice(idx, deleteCount);
242
+ }
232
243
  }
233
- this._engine.dispatchEvent("containerDestroyed", { container: this });
244
+ this._engine.dispatchEvent(EventType.containerDestroyed, { container: this });
234
245
  }
235
246
  draw(force) {
236
247
  if (!guardCheck(this)) {
@@ -244,7 +255,7 @@ export class Container {
244
255
  }
245
256
  this._nextFrame(timestamp);
246
257
  };
247
- this._drawAnimationFrame = requestAnimationFrame((timestamp) => frame(timestamp));
258
+ this._drawAnimationFrame = animate(timestamp => frame(timestamp));
248
259
  }
249
260
  async export(type, options = {}) {
250
261
  for (const [, plugin] of this.plugins) {
@@ -298,13 +309,14 @@ export class Container {
298
309
  this.updateActualOptions();
299
310
  this.canvas.initBackground();
300
311
  this.canvas.resize();
301
- this.zLayers = this.actualOptions.zLayers;
302
- this._duration = getRangeValue(this.actualOptions.duration) * millisecondsToSeconds;
303
- this._delay = getRangeValue(this.actualOptions.delay) * millisecondsToSeconds;
312
+ const { zLayers, duration, delay, fpsLimit, smooth } = this.actualOptions;
313
+ this.zLayers = zLayers;
314
+ this._duration = getRangeValue(duration) * millisecondsToSeconds;
315
+ this._delay = getRangeValue(delay) * millisecondsToSeconds;
304
316
  this._lifeTime = 0;
305
317
  const defaultFpsLimit = 120, minFpsLimit = 0;
306
- this.fpsLimit = this.actualOptions.fpsLimit > minFpsLimit ? this.actualOptions.fpsLimit : defaultFpsLimit;
307
- this._smooth = this.actualOptions.smooth;
318
+ this.fpsLimit = fpsLimit > minFpsLimit ? fpsLimit : defaultFpsLimit;
319
+ this._smooth = smooth;
308
320
  for (const [, drawer] of this.effectDrawers) {
309
321
  await drawer.init?.(this);
310
322
  }
@@ -314,13 +326,13 @@ export class Container {
314
326
  for (const [, plugin] of this.plugins) {
315
327
  await plugin.init?.();
316
328
  }
317
- this._engine.dispatchEvent("containerInit", { container: this });
329
+ this._engine.dispatchEvent(EventType.containerInit, { container: this });
318
330
  await this.particles.init();
319
331
  this.particles.setDensity();
320
332
  for (const [, plugin] of this.plugins) {
321
333
  plugin.particlesSetup?.();
322
334
  }
323
- this._engine.dispatchEvent("particlesSetup", { container: this });
335
+ this._engine.dispatchEvent(EventType.particlesSetup, { container: this });
324
336
  }
325
337
  async loadTheme(name) {
326
338
  if (!guardCheck(this)) {
@@ -334,7 +346,7 @@ export class Container {
334
346
  return;
335
347
  }
336
348
  if (this._drawAnimationFrame !== undefined) {
337
- cancelAnimationFrame(this._drawAnimationFrame);
349
+ cancelAnimation(this._drawAnimationFrame);
338
350
  delete this._drawAnimationFrame;
339
351
  }
340
352
  if (this._paused) {
@@ -346,7 +358,7 @@ export class Container {
346
358
  if (!this.pageHidden) {
347
359
  this._paused = true;
348
360
  }
349
- this._engine.dispatchEvent("containerPaused", { container: this });
361
+ this._engine.dispatchEvent(EventType.containerPaused, { container: this });
350
362
  }
351
363
  play(force) {
352
364
  if (!guardCheck(this)) {
@@ -367,7 +379,7 @@ export class Container {
367
379
  }
368
380
  }
369
381
  }
370
- this._engine.dispatchEvent("containerPlay", { container: this });
382
+ this._engine.dispatchEvent(EventType.containerPlay, { container: this });
371
383
  this.draw(needsUpdate ?? false);
372
384
  }
373
385
  async refresh() {
@@ -377,12 +389,13 @@ export class Container {
377
389
  this.stop();
378
390
  return this.start();
379
391
  }
380
- async reset() {
392
+ async reset(sourceOptions) {
381
393
  if (!guardCheck(this)) {
382
394
  return;
383
395
  }
384
- this._initialSourceOptions = undefined;
385
- this._options = loadContainerOptions(this._engine, this);
396
+ this._initialSourceOptions = sourceOptions;
397
+ this._sourceOptions = sourceOptions;
398
+ this._options = loadContainerOptions(this._engine, this, this._initialSourceOptions, this.sourceOptions);
386
399
  this.actualOptions = loadContainerOptions(this._engine, this, this._options);
387
400
  return this.refresh();
388
401
  }
@@ -392,7 +405,7 @@ export class Container {
392
405
  }
393
406
  await this.init();
394
407
  this.started = true;
395
- await new Promise((resolve) => {
408
+ await new Promise(resolve => {
396
409
  const start = async () => {
397
410
  this._eventListeners.addListeners();
398
411
  if (this.interactivity.element instanceof HTMLElement && this._intersectionObserver) {
@@ -401,7 +414,7 @@ export class Container {
401
414
  for (const [, plugin] of this.plugins) {
402
415
  await plugin.start?.();
403
416
  }
404
- this._engine.dispatchEvent("containerStarted", { container: this });
417
+ this._engine.dispatchEvent(EventType.containerStarted, { container: this });
405
418
  this.play();
406
419
  resolve();
407
420
  };
@@ -432,7 +445,7 @@ export class Container {
432
445
  this.plugins.delete(key);
433
446
  }
434
447
  this._sourceOptions = this._options;
435
- this._engine.dispatchEvent("containerStopped", { container: this });
448
+ this._engine.dispatchEvent(EventType.containerStopped, { container: this });
436
449
  }
437
450
  updateActualOptions() {
438
451
  this.actualOptions.responsive = [];
@@ -1,11 +1,13 @@
1
1
  import { errorPrefix, generatedAttribute } from "./Utils/Constants.js";
2
2
  import { executeOnSingleOrMultiple, getLogger, itemFromSingleOrMultiple } from "../Utils/Utils.js";
3
+ import { Container } from "./Container.js";
3
4
  import { EventDispatcher } from "../Utils/EventDispatcher.js";
5
+ import { EventType } from "../Enums/Types/EventType.js";
4
6
  import { getRandom } from "../Utils/NumberUtils.js";
5
7
  async function getItemsFromInitializer(container, map, initializers, force = false) {
6
8
  let res = map.get(container);
7
9
  if (!res || force) {
8
- res = await Promise.all([...initializers.values()].map((t) => t(container)));
10
+ res = await Promise.all([...initializers.values()].map(t => t(container)));
9
11
  map.set(container, res);
10
12
  }
11
13
  return res;
@@ -22,6 +24,46 @@ async function getDataFromUrl(data) {
22
24
  getLogger().error(`${errorPrefix} ${response.status} while retrieving config file`);
23
25
  return data.fallback;
24
26
  }
27
+ const generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", getCanvasFromContainer = (domContainer) => {
28
+ let canvasEl;
29
+ if (domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag) {
30
+ canvasEl = domContainer;
31
+ if (!canvasEl.dataset[generatedAttribute]) {
32
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
33
+ }
34
+ }
35
+ else {
36
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag);
37
+ if (existingCanvases.length) {
38
+ const firstIndex = 0;
39
+ canvasEl = existingCanvases[firstIndex];
40
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
41
+ }
42
+ else {
43
+ canvasEl = document.createElement(canvasTag);
44
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
45
+ domContainer.appendChild(canvasEl);
46
+ }
47
+ }
48
+ const fullPercent = "100%";
49
+ if (!canvasEl.style.width) {
50
+ canvasEl.style.width = fullPercent;
51
+ }
52
+ if (!canvasEl.style.height) {
53
+ canvasEl.style.height = fullPercent;
54
+ }
55
+ return canvasEl;
56
+ }, getDomContainer = (id, source) => {
57
+ let domContainer = source ?? document.getElementById(id);
58
+ if (domContainer) {
59
+ return domContainer;
60
+ }
61
+ domContainer = document.createElement("div");
62
+ domContainer.id = id;
63
+ domContainer.dataset[generatedAttribute] = generatedTrue;
64
+ document.body.append(domContainer);
65
+ return domContainer;
66
+ };
25
67
  export class Engine {
26
68
  constructor() {
27
69
  this._configs = new Map();
@@ -49,16 +91,19 @@ export class Engine {
49
91
  }
50
92
  return res;
51
93
  }
94
+ get items() {
95
+ return this._domArray;
96
+ }
52
97
  get version() {
53
- return "3.3.0";
98
+ return "3.5.0";
54
99
  }
55
100
  addConfig(config) {
56
101
  const key = config.key ?? config.name ?? "default";
57
102
  this._configs.set(key, config);
58
- this._eventDispatcher.dispatchEvent("configAdded", { data: { name: key, config } });
103
+ this._eventDispatcher.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
59
104
  }
60
105
  async addEffect(effect, drawer, refresh = true) {
61
- executeOnSingleOrMultiple(effect, (type) => {
106
+ executeOnSingleOrMultiple(effect, type => {
62
107
  if (!this.getEffectDrawer(type)) {
63
108
  this.effectDrawers.set(type, drawer);
64
109
  }
@@ -98,12 +143,13 @@ export class Engine {
98
143
  }
99
144
  await this.refresh(refresh);
100
145
  }
101
- async addShape(shape, drawer, refresh = true) {
102
- executeOnSingleOrMultiple(shape, (type) => {
103
- if (!this.getShapeDrawer(type)) {
104
- this.shapeDrawers.set(type, drawer);
146
+ async addShape(drawer, refresh = true) {
147
+ for (const validType of drawer.validTypes) {
148
+ if (this.getShapeDrawer(validType)) {
149
+ continue;
105
150
  }
106
- });
151
+ this.shapeDrawers.set(validType, drawer);
152
+ }
107
153
  await this.refresh(refresh);
108
154
  }
109
155
  clearPlugins(container) {
@@ -115,16 +161,10 @@ export class Engine {
115
161
  this._eventDispatcher.dispatchEvent(type, args);
116
162
  }
117
163
  dom() {
118
- return this._domArray;
164
+ return this.items;
119
165
  }
120
166
  domItem(index) {
121
- const dom = this.dom(), item = dom[index];
122
- if (!item || item.destroyed) {
123
- const deleteCount = 1;
124
- dom.splice(index, deleteCount);
125
- return;
126
- }
127
- return item;
167
+ return this.item(index);
128
168
  }
129
169
  async getAvailablePlugins(container) {
130
170
  const res = new Map();
@@ -139,16 +179,16 @@ export class Engine {
139
179
  return this.effectDrawers.get(type);
140
180
  }
141
181
  async getInteractors(container, force = false) {
142
- return await getItemsFromInitializer(container, this.interactors, this._initializers.interactors, force);
182
+ return getItemsFromInitializer(container, this.interactors, this._initializers.interactors, force);
143
183
  }
144
184
  async getMovers(container, force = false) {
145
- return await getItemsFromInitializer(container, this.movers, this._initializers.movers, force);
185
+ return getItemsFromInitializer(container, this.movers, this._initializers.movers, force);
146
186
  }
147
187
  getPathGenerator(type) {
148
188
  return this.pathGenerators.get(type);
149
189
  }
150
190
  getPlugin(plugin) {
151
- return this.plugins.find((t) => t.id === plugin);
191
+ return this.plugins.find(t => t.id === plugin);
152
192
  }
153
193
  getPreset(preset) {
154
194
  return this.presets.get(preset);
@@ -163,7 +203,7 @@ export class Engine {
163
203
  return this.shapeDrawers.keys();
164
204
  }
165
205
  async getUpdaters(container, force = false) {
166
- return await getItemsFromInitializer(container, this.updaters, this._initializers.updaters, force);
206
+ return getItemsFromInitializer(container, this.updaters, this._initializers.updaters, force);
167
207
  }
168
208
  init() {
169
209
  if (this._initialized) {
@@ -171,89 +211,57 @@ export class Engine {
171
211
  }
172
212
  this._initialized = true;
173
213
  }
214
+ item(index) {
215
+ const { items } = this, item = items[index];
216
+ if (!item || item.destroyed) {
217
+ const deleteCount = 1;
218
+ items.splice(index, deleteCount);
219
+ return;
220
+ }
221
+ return item;
222
+ }
174
223
  async load(params) {
175
224
  const randomFactor = 10000, id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * randomFactor)}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options;
176
- let domContainer = params.element ?? document.getElementById(id);
177
- if (!domContainer) {
178
- domContainer = document.createElement("div");
179
- domContainer.id = id;
180
- document.body.append(domContainer);
181
- }
182
- const currentOptions = itemFromSingleOrMultiple(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id), minIndex = 0;
225
+ const currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), minIndex = 0, newItem = new Container(this, id, currentOptions);
183
226
  if (oldIndex >= minIndex) {
184
- const old = this.domItem(oldIndex);
227
+ const old = this.item(oldIndex), one = 1, none = 0, deleteCount = old ? one : none;
185
228
  if (old && !old.destroyed) {
186
- old.destroy();
187
- const deleteCount = 1;
188
- dom.splice(oldIndex, deleteCount);
189
- }
190
- }
191
- let canvasEl;
192
- if (domContainer.tagName.toLowerCase() === "canvas") {
193
- canvasEl = domContainer;
194
- canvasEl.dataset[generatedAttribute] = "false";
195
- }
196
- else {
197
- const existingCanvases = domContainer.getElementsByTagName("canvas");
198
- if (existingCanvases.length) {
199
- const firstIndex = 0;
200
- canvasEl = existingCanvases[firstIndex];
201
- canvasEl.dataset[generatedAttribute] = "false";
229
+ old.destroy(false);
202
230
  }
203
- else {
204
- canvasEl = document.createElement("canvas");
205
- canvasEl.dataset[generatedAttribute] = "true";
206
- domContainer.appendChild(canvasEl);
207
- }
208
- }
209
- if (!canvasEl.style.width) {
210
- canvasEl.style.width = "100%";
211
- }
212
- if (!canvasEl.style.height) {
213
- canvasEl.style.height = "100%";
214
- }
215
- const { Container } = await import("./Container.js"), newItem = new Container(this, id, currentOptions);
216
- if (oldIndex >= minIndex) {
217
- const deleteCount = 0;
218
- dom.splice(oldIndex, deleteCount, newItem);
231
+ items.splice(oldIndex, deleteCount, newItem);
219
232
  }
220
233
  else {
221
- dom.push(newItem);
234
+ items.push(newItem);
222
235
  }
236
+ const domContainer = getDomContainer(id, params.element), canvasEl = getCanvasFromContainer(domContainer);
223
237
  newItem.canvas.loadCanvas(canvasEl);
224
238
  await newItem.start();
225
239
  return newItem;
226
240
  }
227
241
  loadOptions(options, sourceOptions) {
228
- for (const plugin of this.plugins) {
229
- plugin.loadOptions(options, sourceOptions);
230
- }
242
+ this.plugins.forEach(plugin => plugin.loadOptions?.(options, sourceOptions));
231
243
  }
232
244
  loadParticlesOptions(container, options, ...sourceOptions) {
233
245
  const updaters = this.updaters.get(container);
234
246
  if (!updaters) {
235
247
  return;
236
248
  }
237
- for (const updater of updaters) {
238
- updater.loadOptions?.(options, ...sourceOptions);
239
- }
249
+ updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
240
250
  }
241
251
  async refresh(refresh = true) {
242
252
  if (!refresh) {
243
253
  return;
244
254
  }
245
- await Promise.all(this.dom().map((t) => t.refresh()));
255
+ await Promise.all(this.items.map(t => t.refresh()));
246
256
  }
247
257
  removeEventListener(type, listener) {
248
258
  this._eventDispatcher.removeEventListener(type, listener);
249
259
  }
250
260
  setOnClickHandler(callback) {
251
- const dom = this.dom();
252
- if (!dom.length) {
261
+ const { items } = this;
262
+ if (!items.length) {
253
263
  throw new Error(`${errorPrefix} can only set click handlers after calling tsParticles.load()`);
254
264
  }
255
- for (const domItem of dom) {
256
- domItem.addClickHandler(callback);
257
- }
265
+ items.forEach(item => item.addClickHandler(callback));
258
266
  }
259
267
  }
@@ -3,10 +3,15 @@ import { calcExactPositionOrRandomFromSize, clamp, degToRad, getDistance, getPar
3
3
  import { deepExtend, getPosition, initParticleNumericAnimationValue, isInArray, itemFromSingleOrMultiple, } from "../Utils/Utils.js";
4
4
  import { errorPrefix, millisecondsToSeconds } from "./Utils/Constants.js";
5
5
  import { getHslFromAnimation, rangeColorToRgb } from "../Utils/ColorUtils.js";
6
+ import { EventType } from "../Enums/Types/EventType.js";
6
7
  import { Interactivity } from "../Options/Classes/Interactivity/Interactivity.js";
8
+ import { MoveDirection } from "../Enums/Directions/MoveDirection.js";
9
+ import { OutMode } from "../Enums/Modes/OutMode.js";
10
+ import { ParticleOutType } from "../Enums/Types/ParticleOutType.js";
11
+ import { PixelMode } from "../Enums/Modes/PixelMode.js";
7
12
  import { alterHsl } from "../Utils/CanvasUtils.js";
8
13
  import { loadParticlesOptions } from "../Utils/OptionsUtils.js";
9
- const defaultRetryCount = 0, double = 2, half = 0.5, squareExp = 2;
14
+ const defaultRetryCount = 0, double = 2, half = 0.5, squareExp = 2, randomString = "random";
10
15
  function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
11
16
  const effectData = effectOptions.options[effect];
12
17
  if (!effectData) {
@@ -55,7 +60,7 @@ export class Particle {
55
60
  }), pos = Vector3d.create(exactPosition.x, exactPosition.y, zIndex), radius = this.getRadius(), outModes = this.options.move.outModes, fixHorizontal = (outMode) => {
56
61
  fixOutMode({
57
62
  outMode,
58
- checkModes: ["bounce"],
63
+ checkModes: [OutMode.bounce],
59
64
  coord: pos.x,
60
65
  maxCoord: container.canvas.size.width,
61
66
  setCb: (value) => (pos.x += value),
@@ -64,7 +69,7 @@ export class Particle {
64
69
  }, fixVertical = (outMode) => {
65
70
  fixOutMode({
66
71
  outMode,
67
- checkModes: ["bounce"],
72
+ checkModes: [OutMode.bounce],
68
73
  coord: pos.y,
69
74
  maxCoord: container.canvas.size.height,
70
75
  setCb: (value) => (pos.y += value),
@@ -83,7 +88,7 @@ export class Particle {
83
88
  };
84
89
  this._calculateVelocity = () => {
85
90
  const baseVelocity = getParticleBaseVelocity(this.direction), res = baseVelocity.copy(), moveOptions = this.options.move;
86
- if (moveOptions.direction === "inside" || moveOptions.direction === "outside") {
91
+ if (moveOptions.direction === MoveDirection.inside || moveOptions.direction === MoveDirection.outside) {
87
92
  return res;
88
93
  }
89
94
  const rad = degToRad(getRangeValue(moveOptions.angle.value)), radOffset = degToRad(getRangeValue(moveOptions.angle.offset)), range = {
@@ -111,9 +116,9 @@ export class Particle {
111
116
  if (retries >= minRetries && tryCount > retries) {
112
117
  throw new Error(`${errorPrefix} particle is overlapping and can't be placed`);
113
118
  }
114
- return !!this.container.particles.find((particle) => getDistance(pos, particle.position) < radius + particle.getRadius());
119
+ return !!this.container.particles.find(particle => getDistance(pos, particle.position) < radius + particle.getRadius());
115
120
  };
116
- this._getRollColor = (color) => {
121
+ this._getRollColor = color => {
117
122
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
118
123
  return color;
119
124
  }
@@ -129,7 +134,7 @@ export class Particle {
129
134
  }
130
135
  return color;
131
136
  };
132
- this._initPosition = (position) => {
137
+ this._initPosition = position => {
133
138
  const container = this.container, zIndexValue = getRangeValue(this.options.zIndex.value), minZ = 0;
134
139
  this.position = this._calcPosition(container, position, clamp(zIndexValue, minZ, container.zLayers));
135
140
  this.initialPosition = this.position.copy();
@@ -137,15 +142,15 @@ export class Particle {
137
142
  this.moveCenter = {
138
143
  ...getPosition(this.options.move.center, canvasSize),
139
144
  radius: this.options.move.center.radius ?? defaultRadius,
140
- mode: this.options.move.center.mode ?? "percent",
145
+ mode: this.options.move.center.mode ?? PixelMode.percent,
141
146
  };
142
147
  this.direction = getParticleDirectionAngle(this.options.move.direction, this.position, this.moveCenter);
143
148
  switch (this.options.move.direction) {
144
- case "inside":
145
- this.outType = "inside";
149
+ case MoveDirection.inside:
150
+ this.outType = ParticleOutType.inside;
146
151
  break;
147
- case "outside":
148
- this.outType = "outside";
152
+ case MoveDirection.outside:
153
+ this.outType = ParticleOutType.outside;
149
154
  break;
150
155
  }
151
156
  this.offset = Vector.origin;
@@ -168,7 +173,7 @@ export class Particle {
168
173
  updater.particleDestroyed?.(this, override);
169
174
  }
170
175
  pathGenerator?.reset(this);
171
- this._engine.dispatchEvent("particleDestroyed", {
176
+ this._engine.dispatchEvent(EventType.particleDestroyed, {
172
177
  container: this.container,
173
178
  data: {
174
179
  particle: this,
@@ -213,14 +218,15 @@ export class Particle {
213
218
  this.lastPathTime = 0;
214
219
  this.destroyed = false;
215
220
  this.unbreakable = false;
221
+ this.isRotating = false;
216
222
  this.rotation = 0;
217
223
  this.misplaced = false;
218
224
  this.retina = {
219
225
  maxDistance: {},
220
226
  };
221
- this.outType = "normal";
227
+ this.outType = ParticleOutType.normal;
222
228
  this.ignoresResizeRatio = true;
223
- const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles), effectType = particlesOptions.effect.type, shapeType = particlesOptions.shape.type, { reduceDuplicates } = particlesOptions;
229
+ const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles), { reduceDuplicates } = particlesOptions, effectType = particlesOptions.effect.type, shapeType = particlesOptions.shape.type;
224
230
  this.effect = itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
225
231
  this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
226
232
  const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
@@ -240,6 +246,14 @@ export class Particle {
240
246
  }
241
247
  }
242
248
  }
249
+ if (this.effect === randomString) {
250
+ const availableEffects = [...this.container.effectDrawers.keys()];
251
+ this.effect = availableEffects[Math.floor(Math.random() * availableEffects.length)];
252
+ }
253
+ if (this.shape === randomString) {
254
+ const availableShapes = [...this.container.shapeDrawers.keys()];
255
+ this.shape = availableShapes[Math.floor(Math.random() * availableShapes.length)];
256
+ }
243
257
  this.effectData = loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates);
244
258
  this.shapeData = loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates);
245
259
  particlesOptions.load(overrideOptions);