@tsparticles/engine 3.0.0-beta.2 → 3.0.0-beta.4

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 (186) hide show
  1. package/browser/Core/Canvas.js +2 -2
  2. package/browser/Core/Container.js +39 -24
  3. package/browser/Core/Engine.js +26 -53
  4. package/browser/Core/Particle.js +88 -53
  5. package/browser/Core/Particles.js +51 -26
  6. package/browser/Core/Retina.js +0 -2
  7. package/browser/Core/Utils/QuadTree.js +1 -1
  8. package/browser/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  9. package/browser/Options/Classes/ColorAnimation.js +4 -24
  10. package/browser/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  11. package/browser/Options/Classes/Particles/Effect/Effect.js +32 -0
  12. package/browser/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  13. package/browser/Options/Classes/Particles/Number/ParticlesNumberLimit.js +17 -0
  14. package/browser/Options/Classes/Particles/Opacity/Opacity.js +2 -3
  15. package/browser/Options/Classes/Particles/ParticlesOptions.js +3 -0
  16. package/browser/Options/Classes/Particles/Size/Size.js +2 -3
  17. package/browser/Options/Classes/ValueWithRandom.js +1 -10
  18. package/browser/Utils/CanvasUtils.js +29 -21
  19. package/browser/Utils/ColorUtils.js +24 -38
  20. package/browser/Utils/NumberUtils.js +7 -16
  21. package/browser/Utils/Utils.js +13 -7
  22. package/browser/export-types.js +4 -2
  23. package/browser/exports.js +2 -3
  24. package/cjs/Core/Canvas.js +2 -2
  25. package/cjs/Core/Container.js +39 -24
  26. package/cjs/Core/Engine.js +25 -52
  27. package/cjs/Core/Particle.js +87 -52
  28. package/cjs/Core/Particles.js +51 -26
  29. package/cjs/Core/Retina.js +0 -2
  30. package/cjs/Core/Utils/QuadTree.js +1 -1
  31. package/cjs/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  32. package/cjs/Options/Classes/ColorAnimation.js +4 -24
  33. package/cjs/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  34. package/cjs/Options/Classes/Particles/Effect/Effect.js +36 -0
  35. package/cjs/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  36. package/cjs/Options/Classes/Particles/Number/ParticlesNumberLimit.js +21 -0
  37. package/cjs/Options/Classes/Particles/Opacity/Opacity.js +1 -2
  38. package/cjs/Options/Classes/Particles/ParticlesOptions.js +3 -0
  39. package/cjs/Options/Classes/Particles/Size/Size.js +2 -3
  40. package/cjs/Options/Classes/ValueWithRandom.js +1 -10
  41. package/cjs/Utils/CanvasUtils.js +32 -24
  42. package/cjs/Utils/ColorUtils.js +24 -38
  43. package/cjs/Utils/NumberUtils.js +8 -18
  44. package/cjs/Utils/Utils.js +14 -7
  45. package/cjs/export-types.js +4 -2
  46. package/cjs/exports.js +2 -3
  47. package/esm/Core/Canvas.js +2 -2
  48. package/esm/Core/Container.js +39 -24
  49. package/esm/Core/Engine.js +26 -53
  50. package/esm/Core/Particle.js +88 -53
  51. package/esm/Core/Particles.js +51 -26
  52. package/esm/Core/Retina.js +0 -2
  53. package/esm/Core/Utils/QuadTree.js +1 -1
  54. package/esm/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  55. package/esm/Options/Classes/ColorAnimation.js +4 -24
  56. package/esm/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  57. package/esm/Options/Classes/Particles/Effect/Effect.js +32 -0
  58. package/esm/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  59. package/esm/Options/Classes/Particles/Number/ParticlesNumberLimit.js +17 -0
  60. package/esm/Options/Classes/Particles/Opacity/Opacity.js +2 -3
  61. package/esm/Options/Classes/Particles/ParticlesOptions.js +3 -0
  62. package/esm/Options/Classes/Particles/Size/Size.js +2 -3
  63. package/esm/Options/Classes/ValueWithRandom.js +1 -10
  64. package/esm/Utils/CanvasUtils.js +29 -21
  65. package/esm/Utils/ColorUtils.js +24 -38
  66. package/esm/Utils/NumberUtils.js +7 -16
  67. package/esm/Utils/Utils.js +13 -7
  68. package/esm/export-types.js +4 -2
  69. package/esm/exports.js +2 -3
  70. package/package.json +1 -1
  71. package/report.html +4 -22
  72. package/tsparticles.engine.js +461 -347
  73. package/tsparticles.engine.min.js +1 -1
  74. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  75. package/types/Core/Canvas.d.ts +0 -1
  76. package/types/Core/Container.d.ts +9 -8
  77. package/types/Core/Engine.d.ts +9 -5
  78. package/types/Core/Interfaces/IContainerPlugin.d.ts +2 -3
  79. package/types/Core/Interfaces/IEffectDrawer.d.ts +10 -0
  80. package/types/Core/Interfaces/IExternalInteractor.d.ts +3 -4
  81. package/types/Core/Interfaces/IInteractor.d.ts +3 -3
  82. package/types/Core/Interfaces/IParticleRetinaProps.d.ts +0 -1
  83. package/types/Core/Interfaces/IParticlesInteractor.d.ts +3 -3
  84. package/types/Core/Interfaces/IShapeDrawData.d.ts +10 -0
  85. package/types/Core/Interfaces/IShapeDrawer.d.ts +11 -9
  86. package/types/Core/Particle.d.ts +7 -5
  87. package/types/Core/Particles.d.ts +10 -7
  88. package/types/Core/Retina.d.ts +0 -1
  89. package/types/Core/Utils/ExternalInteractorBase.d.ts +4 -4
  90. package/types/Core/Utils/InteractionManager.d.ts +1 -2
  91. package/types/Core/Utils/ParticlesInteractorBase.d.ts +5 -5
  92. package/types/Enums/Modes/LimitMode.d.ts +4 -0
  93. package/types/Enums/Types/EasingType.d.ts +3 -0
  94. package/types/Enums/Types/EventType.d.ts +1 -0
  95. package/types/Options/Classes/BackgroundMask/BackgroundMask.d.ts +1 -1
  96. package/types/Options/Classes/ColorAnimation.d.ts +2 -7
  97. package/types/Options/Classes/Interactivity/Events/ClickEvent.d.ts +1 -2
  98. package/types/Options/Classes/Interactivity/Events/DivEvent.d.ts +1 -2
  99. package/types/Options/Classes/Interactivity/Events/Events.d.ts +3 -3
  100. package/types/Options/Classes/Interactivity/Events/HoverEvent.d.ts +2 -3
  101. package/types/Options/Classes/Interactivity/Interactivity.d.ts +2 -2
  102. package/types/Options/Classes/Options.d.ts +6 -6
  103. package/types/Options/Classes/Particles/Bounce/ParticlesBounce.d.ts +2 -2
  104. package/types/Options/Classes/Particles/Collisions/Collisions.d.ts +3 -3
  105. package/types/Options/Classes/Particles/Effect/Effect.d.ts +13 -0
  106. package/types/Options/Classes/Particles/Move/Move.d.ts +8 -8
  107. package/types/Options/Classes/Particles/Move/MoveTrail.d.ts +1 -1
  108. package/types/Options/Classes/Particles/Number/ParticlesNumber.d.ts +3 -2
  109. package/types/Options/Classes/Particles/Number/ParticlesNumberLimit.d.ts +10 -0
  110. package/types/Options/Classes/Particles/Opacity/Opacity.d.ts +3 -3
  111. package/types/Options/Classes/Particles/ParticlesOptions.d.ts +12 -10
  112. package/types/Options/Classes/Particles/Size/Size.d.ts +3 -3
  113. package/types/Options/Classes/Theme/Theme.d.ts +1 -1
  114. package/types/Options/Classes/ValueWithRandom.d.ts +2 -4
  115. package/types/Options/Interfaces/IValueWithRandom.d.ts +0 -2
  116. package/types/Options/Interfaces/Interactivity/Events/IClickEvent.d.ts +1 -2
  117. package/types/Options/Interfaces/Interactivity/Events/IDivEvent.d.ts +1 -2
  118. package/types/Options/Interfaces/Interactivity/Events/IHoverEvent.d.ts +1 -2
  119. package/types/Options/Interfaces/Particles/Effect/IEffect.d.ts +8 -0
  120. package/types/Options/Interfaces/Particles/IParticlesOptions.d.ts +2 -0
  121. package/types/Options/Interfaces/Particles/Number/IParticlesNumber.d.ts +2 -1
  122. package/types/Options/Interfaces/Particles/Number/IParticlesNumberLimit.d.ts +5 -0
  123. package/types/Types/CustomEventArgs.d.ts +1 -1
  124. package/types/Utils/CanvasUtils.d.ts +12 -3
  125. package/types/Utils/ColorUtils.d.ts +2 -2
  126. package/types/Utils/NumberUtils.d.ts +0 -2
  127. package/types/Utils/Utils.d.ts +6 -6
  128. package/types/export-types.d.ts +5 -2
  129. package/types/exports.d.ts +2 -3
  130. package/umd/Core/Canvas.js +2 -2
  131. package/umd/Core/Container.js +40 -25
  132. package/umd/Core/Engine.js +25 -52
  133. package/umd/Core/Particle.js +87 -52
  134. package/umd/Core/Particles.js +51 -26
  135. package/umd/Core/Retina.js +0 -2
  136. package/umd/Core/Utils/QuadTree.js +1 -1
  137. package/umd/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  138. package/umd/Options/Classes/ColorAnimation.js +5 -25
  139. package/umd/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  140. package/umd/Options/Classes/Particles/Effect/Effect.js +46 -0
  141. package/umd/Options/Classes/Particles/Number/ParticlesNumber.js +4 -6
  142. package/umd/Options/Classes/{Random.js → Particles/Number/ParticlesNumberLimit.js} +9 -9
  143. package/umd/Options/Classes/Particles/Opacity/Opacity.js +1 -2
  144. package/umd/Options/Classes/Particles/ParticlesOptions.js +4 -1
  145. package/umd/Options/Classes/Particles/Size/Size.js +3 -4
  146. package/umd/Options/Classes/ValueWithRandom.js +2 -11
  147. package/umd/Utils/CanvasUtils.js +32 -24
  148. package/umd/Utils/ColorUtils.js +24 -38
  149. package/umd/Utils/NumberUtils.js +9 -19
  150. package/umd/Utils/Utils.js +14 -7
  151. package/umd/export-types.js +5 -3
  152. package/umd/exports.js +3 -4
  153. package/browser/Options/Classes/Random.js +0 -17
  154. package/cjs/Options/Classes/Random.js +0 -21
  155. package/cjs/Types/ShapeDrawerFunctions.js +0 -2
  156. package/esm/Options/Classes/Random.js +0 -17
  157. package/esm/Options/Interfaces/IRandom.js +0 -1
  158. package/esm/Types/ShapeDrawerFunctions.js +0 -1
  159. package/types/Core/Interfaces/IParticle.d.ts +0 -48
  160. package/types/Enums/Modes/ClickMode.d.ts +0 -9
  161. package/types/Enums/Modes/DivMode.d.ts +0 -5
  162. package/types/Enums/Modes/HoverMode.d.ts +0 -11
  163. package/types/Options/Classes/Random.d.ts +0 -9
  164. package/types/Options/Interfaces/IRandom.d.ts +0 -4
  165. package/types/Types/ShapeDrawerFunctions.d.ts +0 -10
  166. package/umd/Types/ShapeDrawerFunctions.js +0 -12
  167. /package/browser/Core/Interfaces/{IParticle.js → IEffectDrawer.js} +0 -0
  168. /package/browser/{Enums/Modes/ClickMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  169. /package/browser/Enums/Modes/{DivMode.js → LimitMode.js} +0 -0
  170. /package/browser/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  171. /package/browser/Options/Interfaces/{IRandom.js → Particles/Number/IParticlesNumberLimit.js} +0 -0
  172. /package/cjs/Core/Interfaces/{IParticle.js → IEffectDrawer.js} +0 -0
  173. /package/cjs/{Enums/Modes/ClickMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  174. /package/cjs/Enums/Modes/{DivMode.js → LimitMode.js} +0 -0
  175. /package/cjs/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  176. /package/cjs/Options/Interfaces/{IRandom.js → Particles/Number/IParticlesNumberLimit.js} +0 -0
  177. /package/{browser/Types/ShapeDrawerFunctions.js → esm/Core/Interfaces/IEffectDrawer.js} +0 -0
  178. /package/esm/Core/Interfaces/{IParticle.js → IShapeDrawData.js} +0 -0
  179. /package/esm/Enums/Modes/{ClickMode.js → LimitMode.js} +0 -0
  180. /package/esm/{Enums/Modes/DivMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  181. /package/esm/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Number/IParticlesNumberLimit.js} +0 -0
  182. /package/umd/Core/Interfaces/{IParticle.js → IEffectDrawer.js} +0 -0
  183. /package/umd/{Enums/Modes/ClickMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  184. /package/umd/Enums/Modes/{DivMode.js → LimitMode.js} +0 -0
  185. /package/umd/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  186. /package/umd/Options/Interfaces/{IRandom.js → Particles/Number/IParticlesNumberLimit.js} +0 -0
@@ -7,16 +7,29 @@ import { Rectangle } from "./Utils/Rectangle.js";
7
7
  import { errorPrefix } from "./Utils/Constants.js";
8
8
  const qTreeCapacity = 4;
9
9
  const qTreeRectangle = (canvasSize) => {
10
- return new Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, (canvasSize.width * 3) / 2, (canvasSize.height * 3) / 2);
10
+ const { height, width } = canvasSize, posOffset = -0.25, sizeFactor = 1.5;
11
+ return new Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
11
12
  };
12
13
  export class Particles {
13
14
  constructor(engine, container) {
14
15
  this._applyDensity = (options, manualCount, group) => {
16
+ const numberOptions = options.number;
15
17
  if (!options.number.density?.enable) {
18
+ if (group === undefined) {
19
+ this._limit = numberOptions.limit.value;
20
+ }
21
+ else {
22
+ this._groupLimits.set(group, numberOptions.limit.value);
23
+ }
16
24
  return;
17
25
  }
18
- const numberOptions = options.number, densityFactor = this._initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit > 0 ? numberOptions.limit : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount, particlesCount = Math.min(this.count, this.filter((t) => t.group === group).length);
19
- this.limit = numberOptions.limit * densityFactor;
26
+ 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);
27
+ if (group === undefined) {
28
+ this._limit = numberOptions.limit.value * densityFactor;
29
+ }
30
+ else {
31
+ this._groupLimits.set(group, numberOptions.limit.value * densityFactor);
32
+ }
20
33
  if (particlesCount < particlesNumber) {
21
34
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
22
35
  }
@@ -34,7 +47,7 @@ export class Particles {
34
47
  };
35
48
  this._pushParticle = (position, overrideOptions, group, initializer) => {
36
49
  try {
37
- let particle = this.pool.pop();
50
+ let particle = this._pool.pop();
38
51
  if (particle) {
39
52
  particle.init(this._nextId, position, overrideOptions, group);
40
53
  }
@@ -73,7 +86,7 @@ export class Particles {
73
86
  const zIdx = this._zArray.indexOf(particle);
74
87
  this._array.splice(index, 1);
75
88
  this._zArray.splice(zIdx, 1);
76
- this.pool.push(particle);
89
+ this._pool.push(particle);
77
90
  this._engine.dispatchEvent("particleRemoved", {
78
91
  container: this._container,
79
92
  data: {
@@ -87,10 +100,11 @@ export class Particles {
87
100
  this._nextId = 0;
88
101
  this._array = [];
89
102
  this._zArray = [];
90
- this.pool = [];
91
- this.limit = 0;
92
- this.needsSort = false;
93
- this.lastZIndex = 0;
103
+ this._pool = [];
104
+ this._limit = 0;
105
+ this._groupLimits = new Map();
106
+ this._needsSort = false;
107
+ this._lastZIndex = 0;
94
108
  this._interactionManager = new InteractionManager(engine, container);
95
109
  const canvasSize = container.canvas.size;
96
110
  this.quadTree = new QuadTree(qTreeRectangle(canvasSize), qTreeCapacity);
@@ -107,17 +121,21 @@ export class Particles {
107
121
  }
108
122
  }
109
123
  addParticle(position, overrideOptions, group, initializer) {
110
- this.pushing = true;
111
- const container = this._container, options = container.actualOptions, limit = options.particles.number.limit;
124
+ const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count;
112
125
  if (limit > 0) {
113
- const countToRemove = this.count + 1 - limit;
114
- if (countToRemove > 0) {
115
- this.removeQuantity(countToRemove);
126
+ if (limitOptions.mode === "delete") {
127
+ const countToRemove = currentCount + 1 - limit;
128
+ if (countToRemove > 0) {
129
+ this.removeQuantity(countToRemove);
130
+ }
131
+ }
132
+ else if (limitOptions.mode === "wait") {
133
+ if (currentCount >= limit) {
134
+ return;
135
+ }
116
136
  }
117
137
  }
118
- const res = this._pushParticle(position, overrideOptions, group, initializer);
119
- this.pushing = false;
120
- return res;
138
+ return this._pushParticle(position, overrideOptions, group, initializer);
121
139
  }
122
140
  clear() {
123
141
  this._array = [];
@@ -154,8 +172,8 @@ export class Particles {
154
172
  }
155
173
  init() {
156
174
  const container = this._container, options = container.actualOptions;
157
- this.lastZIndex = 0;
158
- this.needsSort = false;
175
+ this._lastZIndex = 0;
176
+ this._needsSort = false;
159
177
  let handled = false;
160
178
  this.updaters = this._engine.getUpdaters(container, true);
161
179
  this._interactionManager.init();
@@ -217,6 +235,13 @@ export class Particles {
217
235
  }
218
236
  this._applyDensity(options.particles, options.manualParticles.length);
219
237
  }
238
+ setLastZIndex(zIndex) {
239
+ this._lastZIndex = zIndex;
240
+ this._needsSort = this._needsSort || this._lastZIndex < zIndex;
241
+ }
242
+ setResizeFactor(factor) {
243
+ this._resizeFactor = factor;
244
+ }
220
245
  async update(delta) {
221
246
  const container = this._container, particlesToDelete = new Set();
222
247
  this.quadTree = new QuadTree(qTreeRectangle(container.canvas.size), qTreeCapacity);
@@ -224,10 +249,10 @@ export class Particles {
224
249
  pathGenerator.update();
225
250
  }
226
251
  for (const [, plugin] of container.plugins) {
227
- plugin.update && plugin.update(delta);
252
+ plugin.update && (await plugin.update(delta));
228
253
  }
254
+ const resizeFactor = this._resizeFactor;
229
255
  for (const particle of this._array) {
230
- const resizeFactor = container.canvas.resizeFactor;
231
256
  if (resizeFactor && !particle.ignoresResizeRatio) {
232
257
  particle.position.x *= resizeFactor.width;
233
258
  particle.position.y *= resizeFactor.height;
@@ -255,7 +280,7 @@ export class Particles {
255
280
  const checkDelete = (p) => !particlesToDelete.has(p);
256
281
  this._array = this.filter(checkDelete);
257
282
  this._zArray = this._zArray.filter(checkDelete);
258
- this.pool.push(...particlesToDelete);
283
+ this._pool.push(...particlesToDelete);
259
284
  }
260
285
  await this._interactionManager.externalInteract(delta);
261
286
  for (const particle of this._array) {
@@ -266,12 +291,12 @@ export class Particles {
266
291
  await this._interactionManager.particlesInteract(particle, delta);
267
292
  }
268
293
  }
269
- delete container.canvas.resizeFactor;
270
- if (this.needsSort) {
294
+ delete this._resizeFactor;
295
+ if (this._needsSort) {
271
296
  const zArray = this._zArray;
272
297
  zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
273
- this.lastZIndex = zArray[zArray.length - 1].position.z;
274
- this.needsSort = false;
298
+ this._lastZIndex = zArray[zArray.length - 1].position.z;
299
+ this._needsSort = false;
275
300
  }
276
301
  }
277
302
  }
@@ -17,13 +17,11 @@ export class Retina {
17
17
  canvas.size.height = element.offsetHeight * ratio;
18
18
  }
19
19
  const particles = options.particles, moveOptions = particles.move;
20
- this.attractDistance = getRangeValue(moveOptions.attract.distance) * ratio;
21
20
  this.maxSpeed = getRangeValue(moveOptions.gravity.maxSpeed) * ratio;
22
21
  this.sizeAnimationSpeed = getRangeValue(particles.size.animation.speed) * ratio;
23
22
  }
24
23
  initParticle(particle) {
25
24
  const options = particle.options, ratio = this.pixelRatio, moveOptions = options.move, moveDistance = moveOptions.distance, props = particle.retina;
26
- props.attractDistance = getRangeValue(moveOptions.attract.distance) * ratio;
27
25
  props.moveDrift = getRangeValue(moveOptions.drift) * ratio;
28
26
  props.moveSpeed = getRangeValue(moveOptions.speed) * ratio;
29
27
  props.sizeAnimationSpeed = getRangeValue(options.size.animation.speed) * ratio;
@@ -8,7 +8,7 @@ export class QuadTree {
8
8
  this._subdivide = () => {
9
9
  const { x, y } = this.rectangle.position, { width, height } = this.rectangle.size, { capacity } = this;
10
10
  for (let i = 0; i < 4; i++) {
11
- this._subs.push(new QuadTree(new Rectangle(x + (width / 2) * (i % 2), y + (height / 2) * (Math.round(i / 2) - (i % 2)), width / 2, height / 2), capacity));
11
+ this._subs.push(new QuadTree(new 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));
12
12
  }
13
13
  this._divided = true;
14
14
  };
@@ -14,8 +14,7 @@ export class BackgroundMask {
14
14
  this.composite = data.composite;
15
15
  }
16
16
  if (data.cover !== undefined) {
17
- const cover = data.cover;
18
- const color = (isString(data.cover) ? { color: data.cover } : data.cover);
17
+ const cover = data.cover, color = (isString(data.cover) ? { color: data.cover } : data.cover);
19
18
  this.cover.load(cover.color !== undefined ? cover : { color: color });
20
19
  }
21
20
  if (data.enable !== undefined) {
@@ -1,38 +1,18 @@
1
+ import { AnimationOptions } from "./AnimationOptions.js";
1
2
  import { setRangeValue } from "../../Utils/NumberUtils.js";
2
- export class ColorAnimation {
3
+ export class ColorAnimation extends AnimationOptions {
3
4
  constructor() {
4
- this.count = 0;
5
- this.enable = false;
5
+ super();
6
6
  this.offset = 0;
7
- this.speed = 1;
8
- this.delay = 0;
9
- this.decay = 0;
10
7
  this.sync = true;
11
8
  }
12
9
  load(data) {
10
+ super.load(data);
13
11
  if (!data) {
14
12
  return;
15
13
  }
16
- if (data.count !== undefined) {
17
- this.count = setRangeValue(data.count);
18
- }
19
- if (data.enable !== undefined) {
20
- this.enable = data.enable;
21
- }
22
14
  if (data.offset !== undefined) {
23
15
  this.offset = setRangeValue(data.offset);
24
16
  }
25
- if (data.speed !== undefined) {
26
- this.speed = setRangeValue(data.speed);
27
- }
28
- if (data.decay !== undefined) {
29
- this.decay = setRangeValue(data.decay);
30
- }
31
- if (data.delay !== undefined) {
32
- this.delay = setRangeValue(data.delay);
33
- }
34
- if (data.sync !== undefined) {
35
- this.sync = data.sync;
36
- }
37
17
  }
38
18
  }
@@ -2,7 +2,6 @@ import { ValueWithRandom } from "../../ValueWithRandom.js";
2
2
  export class ParticlesBounceFactor extends ValueWithRandom {
3
3
  constructor() {
4
4
  super();
5
- this.random.minimumValue = 0.1;
6
5
  this.value = 1;
7
6
  }
8
7
  }
@@ -0,0 +1,32 @@
1
+ import { deepExtend } from "../../../../Utils/Utils.js";
2
+ export class Effect {
3
+ constructor() {
4
+ this.close = true;
5
+ this.fill = true;
6
+ this.options = {};
7
+ this.type = [];
8
+ }
9
+ load(data) {
10
+ if (!data) {
11
+ return;
12
+ }
13
+ const options = data.options;
14
+ if (options !== undefined) {
15
+ for (const effect in options) {
16
+ const item = options[effect];
17
+ if (item) {
18
+ this.options[effect] = deepExtend(this.options[effect] ?? {}, item);
19
+ }
20
+ }
21
+ }
22
+ if (data.close !== undefined) {
23
+ this.close = data.close;
24
+ }
25
+ if (data.fill !== undefined) {
26
+ this.fill = data.fill;
27
+ }
28
+ if (data.type !== undefined) {
29
+ this.type = data.type;
30
+ }
31
+ }
32
+ }
@@ -1,8 +1,9 @@
1
1
  import { ParticlesDensity } from "./ParticlesDensity.js";
2
+ import { ParticlesNumberLimit } from "./ParticlesNumberLimit.js";
2
3
  export class ParticlesNumber {
3
4
  constructor() {
4
5
  this.density = new ParticlesDensity();
5
- this.limit = 0;
6
+ this.limit = new ParticlesNumberLimit();
6
7
  this.value = 0;
7
8
  }
8
9
  load(data) {
@@ -10,10 +11,7 @@ export class ParticlesNumber {
10
11
  return;
11
12
  }
12
13
  this.density.load(data.density);
13
- const limit = data.limit;
14
- if (limit !== undefined) {
15
- this.limit = limit;
16
- }
14
+ this.limit.load(data.limit);
17
15
  if (data.value !== undefined) {
18
16
  this.value = data.value;
19
17
  }
@@ -0,0 +1,17 @@
1
+ export class ParticlesNumberLimit {
2
+ constructor() {
3
+ this.mode = "delete";
4
+ this.value = 0;
5
+ }
6
+ load(data) {
7
+ if (!data) {
8
+ return;
9
+ }
10
+ if (data.mode !== undefined) {
11
+ this.mode = data.mode;
12
+ }
13
+ if (data.value !== undefined) {
14
+ this.value = data.value;
15
+ }
16
+ }
17
+ }
@@ -1,10 +1,9 @@
1
1
  import { OpacityAnimation } from "./OpacityAnimation.js";
2
- import { ValueWithRandom } from "../../ValueWithRandom.js";
3
- export class Opacity extends ValueWithRandom {
2
+ import { RangedAnimationValueWithRandom } from "../../ValueWithRandom.js";
3
+ export class Opacity extends RangedAnimationValueWithRandom {
4
4
  constructor() {
5
5
  super();
6
6
  this.animation = new OpacityAnimation();
7
- this.random.minimumValue = 0.1;
8
7
  this.value = 1;
9
8
  }
10
9
  load(data) {
@@ -1,6 +1,7 @@
1
1
  import { deepExtend, executeOnSingleOrMultiple } from "../../../Utils/Utils.js";
2
2
  import { AnimatableColor } from "../AnimatableColor.js";
3
3
  import { Collisions } from "./Collisions/Collisions.js";
4
+ import { Effect } from "./Effect/Effect.js";
4
5
  import { Move } from "./Move/Move.js";
5
6
  import { Opacity } from "./Opacity/Opacity.js";
6
7
  import { ParticlesBounce } from "./Bounce/ParticlesBounce.js";
@@ -18,6 +19,7 @@ export class ParticlesOptions {
18
19
  this.collisions = new Collisions();
19
20
  this.color = new AnimatableColor();
20
21
  this.color.value = "#fff";
22
+ this.effect = new Effect();
21
23
  this.groups = {};
22
24
  this.move = new Move();
23
25
  this.number = new ParticlesNumber();
@@ -35,6 +37,7 @@ export class ParticlesOptions {
35
37
  }
36
38
  this.bounce.load(data.bounce);
37
39
  this.color.load(AnimatableColor.create(this.color, data.color));
40
+ this.effect.load(data.effect);
38
41
  if (data.groups !== undefined) {
39
42
  for (const group in data.groups) {
40
43
  const item = data.groups[group];
@@ -1,10 +1,9 @@
1
+ import { RangedAnimationValueWithRandom } from "../../ValueWithRandom.js";
1
2
  import { SizeAnimation } from "./SizeAnimation.js";
2
- import { ValueWithRandom } from "../../ValueWithRandom.js";
3
- export class Size extends ValueWithRandom {
3
+ export class Size extends RangedAnimationValueWithRandom {
4
4
  constructor() {
5
5
  super();
6
6
  this.animation = new SizeAnimation();
7
- this.random.minimumValue = 1;
8
7
  this.value = 3;
9
8
  }
10
9
  load(data) {
@@ -1,24 +1,15 @@
1
1
  import { AnimationOptions, RangedAnimationOptions } from "./AnimationOptions.js";
2
- import { Random } from "./Random.js";
3
- import { isBoolean } from "../../Utils/Utils.js";
4
2
  import { setRangeValue } from "../../Utils/NumberUtils.js";
5
3
  export class ValueWithRandom {
6
4
  constructor() {
7
- this.random = new Random();
8
5
  this.value = 0;
9
6
  }
10
7
  load(data) {
11
8
  if (!data) {
12
9
  return;
13
10
  }
14
- if (isBoolean(data.random)) {
15
- this.random.enable = data.random;
16
- }
17
- else {
18
- this.random.load(data.random);
19
- }
20
11
  if (data.value !== undefined) {
21
- this.value = setRangeValue(data.value, this.random.enable ? this.random.minimumValue : undefined);
12
+ this.value = setRangeValue(data.value);
22
13
  }
23
14
  }
24
15
  }
@@ -5,13 +5,6 @@ export function drawLine(context, begin, end) {
5
5
  context.lineTo(end.x, end.y);
6
6
  context.closePath();
7
7
  }
8
- export function drawTriangle(context, p1, p2, p3) {
9
- context.beginPath();
10
- context.moveTo(p1.x, p1.y);
11
- context.lineTo(p2.x, p2.y);
12
- context.lineTo(p3.x, p3.y);
13
- context.closePath();
14
- }
15
8
  export function paintBase(context, dimension, baseColor) {
16
9
  context.fillStyle = baseColor ?? "rgba(0,0,0,0)";
17
10
  context.fillRect(0, 0, dimension.width, dimension.height);
@@ -39,7 +32,6 @@ export function drawParticle(data) {
39
32
  d: rotateData.cos * (transform.d ?? 1),
40
33
  };
41
34
  context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
42
- context.beginPath();
43
35
  if (backgroundMask) {
44
36
  context.globalCompositeOperation = composite;
45
37
  }
@@ -58,39 +50,55 @@ export function drawParticle(data) {
58
50
  if (colorStyles.stroke) {
59
51
  context.strokeStyle = colorStyles.stroke;
60
52
  }
61
- drawShape(container, context, particle, radius, opacity, delta);
53
+ const drawData = { container, context, particle, radius, opacity, delta };
54
+ context.beginPath();
55
+ drawShape(drawData);
56
+ if (particle.shapeClose) {
57
+ context.closePath();
58
+ }
62
59
  if (strokeWidth > 0) {
63
60
  context.stroke();
64
61
  }
65
- if (particle.close) {
66
- context.closePath();
67
- }
68
- if (particle.fill) {
62
+ if (particle.shapeFill) {
69
63
  context.fill();
70
64
  }
71
- drawShapeAfterEffect(container, context, particle, radius, opacity, delta);
65
+ drawShapeAfterDraw(drawData);
66
+ drawEffect(drawData);
72
67
  context.globalCompositeOperation = "source-over";
73
68
  context.setTransform(1, 0, 0, 1, 0, 0);
74
69
  }
75
- export function drawShape(container, context, particle, radius, opacity, delta) {
70
+ export function drawEffect(data) {
71
+ const { container, context, particle, radius, opacity, delta } = data;
72
+ if (!particle.effect) {
73
+ return;
74
+ }
75
+ const drawer = container.effectDrawers.get(particle.effect);
76
+ if (!drawer) {
77
+ return;
78
+ }
79
+ drawer.draw({ context, particle, radius, opacity, delta, pixelRatio: container.retina.pixelRatio });
80
+ }
81
+ export function drawShape(data) {
82
+ const { container, context, particle, radius, opacity, delta } = data;
76
83
  if (!particle.shape) {
77
84
  return;
78
85
  }
79
- const drawer = container.drawers.get(particle.shape);
86
+ const drawer = container.shapeDrawers.get(particle.shape);
80
87
  if (!drawer) {
81
88
  return;
82
89
  }
83
- drawer.draw(context, particle, radius, opacity, delta, container.retina.pixelRatio);
90
+ drawer.draw({ context, particle, radius, opacity, delta, pixelRatio: container.retina.pixelRatio });
84
91
  }
85
- export function drawShapeAfterEffect(container, context, particle, radius, opacity, delta) {
92
+ export function drawShapeAfterDraw(data) {
93
+ const { container, context, particle, radius, opacity, delta } = data;
86
94
  if (!particle.shape) {
87
95
  return;
88
96
  }
89
- const drawer = container.drawers.get(particle.shape);
90
- if (!drawer || !drawer.afterEffect) {
97
+ const drawer = container.shapeDrawers.get(particle.shape);
98
+ if (!drawer || !drawer.afterDraw) {
91
99
  return;
92
100
  }
93
- drawer.afterEffect(context, particle, radius, opacity, delta, container.retina.pixelRatio);
101
+ drawer.afterDraw({ context, particle, radius, opacity, delta, pixelRatio: container.retina.pixelRatio });
94
102
  }
95
103
  export function drawPlugin(context, plugin, delta) {
96
104
  if (!plugin.draw) {
@@ -4,24 +4,6 @@ const randomColorValue = "random", midColorValue = "mid", colorManagers = new Ma
4
4
  export function addColorManager(manager) {
5
5
  colorManagers.set(manager.key, manager);
6
6
  }
7
- function hue2rgb(p, q, t) {
8
- if (t < 0) {
9
- t += 1;
10
- }
11
- if (t > 1) {
12
- t -= 1;
13
- }
14
- if (t < 1 / 6) {
15
- return p + (q - p) * 6 * t;
16
- }
17
- if (t < 1 / 2) {
18
- return q;
19
- }
20
- if (t < 2 / 3) {
21
- return p + (q - p) * (2 / 3 - t) * 6;
22
- }
23
- return p;
24
- }
25
7
  function stringToRgba(input) {
26
8
  for (const [, manager] of colorManagers) {
27
9
  if (input.startsWith(manager.stringPrefix)) {
@@ -91,7 +73,7 @@ export function rangeColorToHsl(color, index, useIndex = true) {
91
73
  export function rgbToHsl(color) {
92
74
  const r1 = color.r / 255, g1 = color.g / 255, b1 = color.b / 255, max = Math.max(r1, g1, b1), min = Math.min(r1, g1, b1), res = {
93
75
  h: 0,
94
- l: (max + min) / 2,
76
+ l: (max + min) * 0.5,
95
77
  s: 0,
96
78
  };
97
79
  if (max !== min) {
@@ -119,26 +101,30 @@ export function stringToRgb(input) {
119
101
  return stringToRgba(input);
120
102
  }
121
103
  export function hslToRgb(hsl) {
122
- const result = { b: 0, g: 0, r: 0 }, hslPercent = {
123
- h: hsl.h / 360,
124
- l: hsl.l / 100,
125
- s: hsl.s / 100,
126
- };
127
- if (!hslPercent.s) {
128
- result.r = result.g = result.b = hslPercent.l;
104
+ const h = ((hsl.h % 360) + 360) % 360, s = Math.max(0, Math.min(100, hsl.s)), l = Math.max(0, Math.min(100, hsl.l)), hNormalized = h / 360, sNormalized = s / 100, lNormalized = l / 100;
105
+ if (s === 0) {
106
+ const grayscaleValue = Math.round(lNormalized * 255);
107
+ return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
129
108
  }
130
- else {
131
- const q = hslPercent.l < 0.5
132
- ? hslPercent.l * (1 + hslPercent.s)
133
- : hslPercent.l + hslPercent.s - hslPercent.l * hslPercent.s, p = 2 * hslPercent.l - q;
134
- result.r = hue2rgb(p, q, hslPercent.h + 1 / 3);
135
- result.g = hue2rgb(p, q, hslPercent.h);
136
- result.b = hue2rgb(p, q, hslPercent.h - 1 / 3);
137
- }
138
- result.r = Math.floor(result.r * 255);
139
- result.g = Math.floor(result.g * 255);
140
- result.b = Math.floor(result.b * 255);
141
- return result;
109
+ const channel = (temp1, temp2, temp3) => {
110
+ if (temp3 < 0) {
111
+ temp3 += 1;
112
+ }
113
+ if (temp3 > 1) {
114
+ temp3 -= 1;
115
+ }
116
+ if (temp3 * 6 < 1) {
117
+ return temp1 + (temp2 - temp1) * 6 * temp3;
118
+ }
119
+ if (temp3 * 2 < 1) {
120
+ return temp2;
121
+ }
122
+ if (temp3 * 3 < 2) {
123
+ return temp1 + (temp2 - temp1) * (2 / 3 - temp3) * 6;
124
+ }
125
+ return temp1;
126
+ }, temp1 = lNormalized < 0.5 ? lNormalized * (1 + sNormalized) : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = 2 * lNormalized - temp1, red = Math.min(255, 255 * channel(temp2, temp1, hNormalized + 1 / 3)), green = Math.min(255, 255 * channel(temp2, temp1, hNormalized)), blue = Math.min(255, 255 * channel(temp2, temp1, hNormalized - 1 / 3));
127
+ return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
142
128
  }
143
129
  export function hslaToRgba(hsla) {
144
130
  const rgbResult = hslToRgb(hsla);
@@ -1,5 +1,5 @@
1
- import { isBoolean, isNumber } from "./Utils.js";
2
1
  import { Vector } from "../Core/Utils/Vector.js";
2
+ import { isNumber } from "./Utils.js";
3
3
  let _random = Math.random;
4
4
  const easings = new Map();
5
5
  export function addEasing(name, easing) {
@@ -52,15 +52,6 @@ export function setRangeValue(source, value) {
52
52
  }
53
53
  : setRangeValue(min, max);
54
54
  }
55
- export function getValue(options) {
56
- const random = options.random, { enable, minimumValue } = isBoolean(random)
57
- ? {
58
- enable: random,
59
- minimumValue: 0,
60
- }
61
- : random;
62
- return enable ? getRangeValue(setRangeValue(options.value, minimumValue)) : getRangeValue(options.value);
63
- }
64
55
  export function getDistances(pointA, pointB) {
65
56
  const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y;
66
57
  return { dx: dx, dy: dy, distance: Math.sqrt(dx ** 2 + dy ** 2) };
@@ -74,21 +65,21 @@ export function getParticleDirectionAngle(direction, position, center) {
74
65
  }
75
66
  switch (direction) {
76
67
  case "top":
77
- return -Math.PI / 2;
68
+ return -Math.PI * 0.5;
78
69
  case "top-right":
79
- return -Math.PI / 4;
70
+ return -Math.PI * 0.25;
80
71
  case "right":
81
72
  return 0;
82
73
  case "bottom-right":
83
- return Math.PI / 4;
74
+ return Math.PI * 0.25;
84
75
  case "bottom":
85
- return Math.PI / 2;
76
+ return Math.PI * 0.5;
86
77
  case "bottom-left":
87
- return (3 * Math.PI) / 4;
78
+ return Math.PI * 0.75;
88
79
  case "left":
89
80
  return Math.PI;
90
81
  case "top-left":
91
- return (-3 * Math.PI) / 4;
82
+ return -Math.PI * 0.75;
92
83
  case "inside":
93
84
  return Math.atan2(center.y - position.y, center.x - position.x);
94
85
  case "outside":