@tsparticles/engine 3.0.0-beta.3 → 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 (177) hide show
  1. package/browser/Core/Canvas.js +2 -2
  2. package/browser/Core/Container.js +36 -19
  3. package/browser/Core/Engine.js +18 -5
  4. package/browser/Core/Particle.js +75 -40
  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 +23 -18
  19. package/browser/Utils/ColorUtils.js +24 -38
  20. package/browser/Utils/NumberUtils.js +7 -16
  21. package/browser/Utils/Utils.js +7 -7
  22. package/browser/export-types.js +4 -0
  23. package/browser/exports.js +2 -3
  24. package/cjs/Core/Canvas.js +2 -2
  25. package/cjs/Core/Container.js +36 -19
  26. package/cjs/Core/Engine.js +18 -5
  27. package/cjs/Core/Particle.js +74 -39
  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/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js +2 -0
  42. package/cjs/Utils/CanvasUtils.js +26 -21
  43. package/cjs/Utils/ColorUtils.js +24 -38
  44. package/cjs/Utils/NumberUtils.js +8 -18
  45. package/cjs/Utils/Utils.js +6 -6
  46. package/cjs/export-types.js +4 -0
  47. package/cjs/exports.js +2 -3
  48. package/esm/Core/Canvas.js +2 -2
  49. package/esm/Core/Container.js +36 -19
  50. package/esm/Core/Engine.js +18 -5
  51. package/esm/Core/Particle.js +75 -40
  52. package/esm/Core/Particles.js +51 -26
  53. package/esm/Core/Retina.js +0 -2
  54. package/esm/Core/Utils/QuadTree.js +1 -1
  55. package/esm/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  56. package/esm/Options/Classes/ColorAnimation.js +4 -24
  57. package/esm/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  58. package/esm/Options/Classes/Particles/Effect/Effect.js +32 -0
  59. package/esm/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  60. package/esm/Options/Classes/Particles/Number/ParticlesNumberLimit.js +17 -0
  61. package/esm/Options/Classes/Particles/Opacity/Opacity.js +2 -3
  62. package/esm/Options/Classes/Particles/ParticlesOptions.js +3 -0
  63. package/esm/Options/Classes/Particles/Size/Size.js +2 -3
  64. package/esm/Options/Classes/ValueWithRandom.js +1 -10
  65. package/esm/Options/Interfaces/Particles/Effect/IEffect.js +1 -0
  66. package/esm/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js +1 -0
  67. package/esm/Utils/CanvasUtils.js +23 -18
  68. package/esm/Utils/ColorUtils.js +24 -38
  69. package/esm/Utils/NumberUtils.js +7 -16
  70. package/esm/Utils/Utils.js +7 -7
  71. package/esm/export-types.js +4 -0
  72. package/esm/exports.js +2 -3
  73. package/package.json +1 -1
  74. package/report.html +4 -22
  75. package/tsparticles.engine.js +387 -283
  76. package/tsparticles.engine.min.js +1 -1
  77. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  78. package/types/Core/Canvas.d.ts +0 -1
  79. package/types/Core/Container.d.ts +8 -7
  80. package/types/Core/Engine.d.ts +7 -2
  81. package/types/Core/Interfaces/IContainerPlugin.d.ts +2 -3
  82. package/types/Core/Interfaces/IEffectDrawer.d.ts +10 -0
  83. package/types/Core/Interfaces/IExternalInteractor.d.ts +3 -4
  84. package/types/Core/Interfaces/IInteractor.d.ts +3 -3
  85. package/types/Core/Interfaces/IParticleRetinaProps.d.ts +0 -1
  86. package/types/Core/Interfaces/IParticlesInteractor.d.ts +3 -3
  87. package/types/Core/Interfaces/IShapeDrawData.d.ts +10 -0
  88. package/types/Core/Interfaces/IShapeDrawer.d.ts +2 -10
  89. package/types/Core/Particle.d.ts +6 -2
  90. package/types/Core/Particles.d.ts +10 -7
  91. package/types/Core/Retina.d.ts +0 -1
  92. package/types/Core/Utils/ExternalInteractorBase.d.ts +4 -4
  93. package/types/Core/Utils/InteractionManager.d.ts +1 -2
  94. package/types/Core/Utils/ParticlesInteractorBase.d.ts +5 -5
  95. package/types/Enums/Modes/LimitMode.d.ts +4 -0
  96. package/types/Enums/Types/EasingType.d.ts +3 -0
  97. package/types/Options/Classes/BackgroundMask/BackgroundMask.d.ts +1 -1
  98. package/types/Options/Classes/ColorAnimation.d.ts +2 -7
  99. package/types/Options/Classes/Interactivity/Events/ClickEvent.d.ts +1 -2
  100. package/types/Options/Classes/Interactivity/Events/DivEvent.d.ts +1 -2
  101. package/types/Options/Classes/Interactivity/Events/Events.d.ts +3 -3
  102. package/types/Options/Classes/Interactivity/Events/HoverEvent.d.ts +2 -3
  103. package/types/Options/Classes/Interactivity/Interactivity.d.ts +2 -2
  104. package/types/Options/Classes/Options.d.ts +6 -6
  105. package/types/Options/Classes/Particles/Bounce/ParticlesBounce.d.ts +2 -2
  106. package/types/Options/Classes/Particles/Collisions/Collisions.d.ts +3 -3
  107. package/types/Options/Classes/Particles/Effect/Effect.d.ts +13 -0
  108. package/types/Options/Classes/Particles/Move/Move.d.ts +8 -8
  109. package/types/Options/Classes/Particles/Move/MoveTrail.d.ts +1 -1
  110. package/types/Options/Classes/Particles/Number/ParticlesNumber.d.ts +3 -2
  111. package/types/Options/Classes/Particles/Number/ParticlesNumberLimit.d.ts +10 -0
  112. package/types/Options/Classes/Particles/Opacity/Opacity.d.ts +3 -3
  113. package/types/Options/Classes/Particles/ParticlesOptions.d.ts +12 -10
  114. package/types/Options/Classes/Particles/Size/Size.d.ts +3 -3
  115. package/types/Options/Classes/Theme/Theme.d.ts +1 -1
  116. package/types/Options/Classes/ValueWithRandom.d.ts +2 -4
  117. package/types/Options/Interfaces/IValueWithRandom.d.ts +0 -2
  118. package/types/Options/Interfaces/Interactivity/Events/IClickEvent.d.ts +1 -2
  119. package/types/Options/Interfaces/Interactivity/Events/IDivEvent.d.ts +1 -2
  120. package/types/Options/Interfaces/Interactivity/Events/IHoverEvent.d.ts +1 -2
  121. package/types/Options/Interfaces/Particles/Effect/IEffect.d.ts +8 -0
  122. package/types/Options/Interfaces/Particles/IParticlesOptions.d.ts +2 -0
  123. package/types/Options/Interfaces/Particles/Number/IParticlesNumber.d.ts +2 -1
  124. package/types/Options/Interfaces/Particles/Number/IParticlesNumberLimit.d.ts +5 -0
  125. package/types/Utils/CanvasUtils.d.ts +2 -2
  126. package/types/Utils/NumberUtils.d.ts +0 -2
  127. package/types/Utils/Utils.d.ts +2 -3
  128. package/types/export-types.d.ts +5 -0
  129. package/types/exports.d.ts +2 -3
  130. package/umd/Core/Canvas.js +2 -2
  131. package/umd/Core/Container.js +36 -19
  132. package/umd/Core/Engine.js +18 -5
  133. package/umd/Core/Particle.js +74 -39
  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/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js +12 -0
  148. package/umd/Utils/CanvasUtils.js +26 -21
  149. package/umd/Utils/ColorUtils.js +24 -38
  150. package/umd/Utils/NumberUtils.js +9 -19
  151. package/umd/Utils/Utils.js +6 -6
  152. package/umd/export-types.js +5 -1
  153. package/umd/exports.js +3 -4
  154. package/browser/Options/Classes/Random.js +0 -17
  155. package/cjs/Options/Classes/Random.js +0 -21
  156. package/esm/Options/Classes/Random.js +0 -17
  157. package/types/Enums/Modes/ClickMode.d.ts +0 -9
  158. package/types/Enums/Modes/DivMode.d.ts +0 -5
  159. package/types/Enums/Modes/HoverMode.d.ts +0 -11
  160. package/types/Options/Classes/Random.d.ts +0 -9
  161. package/types/Options/Interfaces/IRandom.d.ts +0 -4
  162. /package/browser/{Enums/Modes/ClickMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  163. /package/browser/{Enums/Modes/DivMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  164. /package/browser/Enums/Modes/{HoverMode.js → LimitMode.js} +0 -0
  165. /package/browser/Options/Interfaces/{IRandom.js → Particles/Effect/IEffect.js} +0 -0
  166. /package/{esm/Enums/Modes/ClickMode.js → browser/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js} +0 -0
  167. /package/cjs/{Enums/Modes/ClickMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  168. /package/cjs/{Enums/Modes/DivMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  169. /package/cjs/Enums/Modes/{HoverMode.js → LimitMode.js} +0 -0
  170. /package/cjs/Options/Interfaces/{IRandom.js → Particles/Effect/IEffect.js} +0 -0
  171. /package/esm/{Enums/Modes/DivMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  172. /package/esm/{Enums/Modes/HoverMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  173. /package/esm/{Options/Interfaces/IRandom.js → Enums/Modes/LimitMode.js} +0 -0
  174. /package/umd/{Enums/Modes/ClickMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  175. /package/umd/{Enums/Modes/DivMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  176. /package/umd/Enums/Modes/{HoverMode.js → LimitMode.js} +0 -0
  177. /package/umd/Options/Interfaces/{IRandom.js → Particles/Effect/IEffect.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { calcExactPositionOrRandomFromSize, clamp, getDistance, getParticleBaseVelocity, getParticleDirectionAngle, getRandom, getRangeValue, getValue, randomInRange, setRangeValue, } from "../Utils/NumberUtils.js";
1
+ import { calcExactPositionOrRandomFromSize, clamp, getDistance, getParticleBaseVelocity, getParticleDirectionAngle, getRandom, getRangeValue, randomInRange, setRangeValue, } from "../Utils/NumberUtils.js";
2
2
  import { deepExtend, getPosition, initParticleNumericAnimationValue, isInArray, itemFromSingleOrMultiple, } from "../Utils/Utils.js";
3
3
  import { getHslFromAnimation, rangeColorToRgb } from "../Utils/ColorUtils.js";
4
4
  import { Interactivity } from "../Options/Classes/Interactivity/Interactivity.js";
@@ -7,6 +7,16 @@ import { Vector3d } from "./Utils/Vector3d.js";
7
7
  import { alterHsl } from "../Utils/CanvasUtils.js";
8
8
  import { errorPrefix } from "./Utils/Constants.js";
9
9
  import { loadParticlesOptions } from "../Utils/OptionsUtils.js";
10
+ function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
11
+ const effectData = effectOptions.options[effect];
12
+ if (!effectData) {
13
+ return;
14
+ }
15
+ return deepExtend({
16
+ close: effectOptions.close,
17
+ fill: effectOptions.fill,
18
+ }, itemFromSingleOrMultiple(effectData, id, reduceDuplicates));
19
+ }
10
20
  function loadShapeData(shape, shapeOptions, id, reduceDuplicates) {
11
21
  const shapeData = shapeOptions.options[shape];
12
22
  if (!shapeData) {
@@ -76,8 +86,8 @@ export class Particle {
76
86
  return res;
77
87
  }
78
88
  const rad = (Math.PI / 180) * getRangeValue(moveOptions.angle.value), radOffset = (Math.PI / 180) * getRangeValue(moveOptions.angle.offset), range = {
79
- left: radOffset - rad / 2,
80
- right: radOffset + rad / 2,
89
+ left: radOffset - rad * 0.5,
90
+ right: radOffset + rad * 0.5,
81
91
  };
82
92
  if (!moveOptions.straight) {
83
93
  res.angle += randomInRange(setRangeValue(range.left, range.right));
@@ -106,7 +116,7 @@ export class Particle {
106
116
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
107
117
  return color;
108
118
  }
109
- const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1, backSum = this.roll.horizontal ? Math.PI / 2 : 0, rolled = Math.floor(((this.roll.angle ?? 0) + backSum) / (Math.PI / backFactor)) % 2;
119
+ 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;
110
120
  if (!rolled) {
111
121
  return color;
112
122
  }
@@ -151,18 +161,12 @@ export class Particle {
151
161
  this.slow.inRange = false;
152
162
  const container = this.container, pathGenerator = this.pathGenerator;
153
163
  for (const [, plugin] of container.plugins) {
154
- if (plugin.particleDestroyed) {
155
- plugin.particleDestroyed(this, override);
156
- }
164
+ plugin.particleDestroyed && plugin.particleDestroyed(this, override);
157
165
  }
158
166
  for (const updater of container.particles.updaters) {
159
- if (updater.particleDestroyed) {
160
- updater.particleDestroyed(this, override);
161
- }
162
- }
163
- if (pathGenerator) {
164
- pathGenerator.reset(this);
167
+ updater.particleDestroyed && updater.particleDestroyed(this, override);
165
168
  }
169
+ pathGenerator && pathGenerator.reset(this);
166
170
  }
167
171
  draw(delta) {
168
172
  const container = this.container, canvas = container.canvas;
@@ -175,7 +179,7 @@ export class Particle {
175
179
  return this._getRollColor(this.bubble.color ?? getHslFromAnimation(this.color));
176
180
  }
177
181
  getMass() {
178
- return (this.getRadius() ** 2 * Math.PI) / 2;
182
+ return this.getRadius() ** 2 * Math.PI * 0.5;
179
183
  }
180
184
  getPosition() {
181
185
  return {
@@ -194,9 +198,11 @@ export class Particle {
194
198
  const container = this.container, engine = this._engine;
195
199
  this.id = id;
196
200
  this.group = group;
197
- this.fill = true;
201
+ this.effectClose = true;
202
+ this.effectFill = true;
203
+ this.shapeClose = true;
204
+ this.shapeFill = true;
198
205
  this.pathRotation = false;
199
- this.close = true;
200
206
  this.lastPathTime = 0;
201
207
  this.destroyed = false;
202
208
  this.unbreakable = false;
@@ -207,18 +213,33 @@ export class Particle {
207
213
  };
208
214
  this.outType = "normal";
209
215
  this.ignoresResizeRatio = true;
210
- const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles), shapeType = particlesOptions.shape.type, { reduceDuplicates } = particlesOptions;
216
+ 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;
217
+ this.effect = itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
211
218
  this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
212
- const shapeOptions = particlesOptions.shape;
213
- if (overrideOptions && overrideOptions.shape && overrideOptions.shape.type) {
214
- const overrideShapeType = overrideOptions.shape.type, shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
215
- if (shape) {
216
- this.shape = shape;
217
- shapeOptions.load(overrideOptions.shape);
219
+ const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
220
+ if (overrideOptions) {
221
+ if (overrideOptions.effect && overrideOptions.effect.type) {
222
+ const overrideEffectType = overrideOptions.effect.type, effect = itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
223
+ if (effect) {
224
+ this.effect = effect;
225
+ effectOptions.load(overrideOptions.effect);
226
+ }
227
+ }
228
+ if (overrideOptions.shape && overrideOptions.shape.type) {
229
+ const overrideShapeType = overrideOptions.shape.type, shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
230
+ if (shape) {
231
+ this.shape = shape;
232
+ shapeOptions.load(overrideOptions.shape);
233
+ }
218
234
  }
219
235
  }
236
+ this.effectData = loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates);
220
237
  this.shapeData = loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates);
221
238
  particlesOptions.load(overrideOptions);
239
+ const effectData = this.effectData;
240
+ if (effectData) {
241
+ particlesOptions.load(effectData.particles);
242
+ }
222
243
  const shapeData = this.shapeData;
223
244
  if (shapeData) {
224
245
  particlesOptions.load(shapeData.particles);
@@ -227,11 +248,13 @@ export class Particle {
227
248
  interactivity.load(container.actualOptions.interactivity);
228
249
  interactivity.load(particlesOptions.interactivity);
229
250
  this.interactivity = interactivity;
230
- this.fill = shapeData?.fill ?? particlesOptions.shape.fill;
231
- this.close = shapeData?.close ?? particlesOptions.shape.close;
251
+ this.effectFill = effectData?.fill ?? particlesOptions.effect.fill;
252
+ this.effectClose = effectData?.close ?? particlesOptions.effect.close;
253
+ this.shapeFill = shapeData?.fill ?? particlesOptions.shape.fill;
254
+ this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
232
255
  this.options = particlesOptions;
233
256
  const pathOptions = this.options.move.path;
234
- this.pathDelay = getValue(pathOptions.delay) * 1000;
257
+ this.pathDelay = getRangeValue(pathOptions.delay.value) * 1000;
235
258
  if (pathOptions.generator) {
236
259
  this.pathGenerator = this._engine.getPathGenerator(pathOptions.generator);
237
260
  if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
@@ -252,34 +275,46 @@ export class Particle {
252
275
  this.velocity = this.initialVelocity.copy();
253
276
  this.moveDecay = 1 - getRangeValue(this.options.move.decay);
254
277
  const particles = container.particles;
255
- particles.needsSort = particles.needsSort || particles.lastZIndex < this.position.z;
256
- particles.lastZIndex = this.position.z;
278
+ particles.setLastZIndex(this.position.z);
257
279
  this.zIndexFactor = this.position.z / container.zLayers;
258
280
  this.sides = 24;
259
- let drawer = container.drawers.get(this.shape);
260
- if (!drawer) {
261
- drawer = this._engine.getShapeDrawer(this.shape);
262
- if (drawer) {
263
- container.drawers.set(this.shape, drawer);
281
+ let effectDrawer = container.effectDrawers.get(this.effect);
282
+ if (!effectDrawer) {
283
+ effectDrawer = this._engine.getEffectDrawer(this.effect);
284
+ if (effectDrawer) {
285
+ container.effectDrawers.set(this.effect, effectDrawer);
286
+ }
287
+ }
288
+ if (effectDrawer && effectDrawer.loadEffect) {
289
+ effectDrawer.loadEffect(this);
290
+ }
291
+ let shapeDrawer = container.shapeDrawers.get(this.shape);
292
+ if (!shapeDrawer) {
293
+ shapeDrawer = this._engine.getShapeDrawer(this.shape);
294
+ if (shapeDrawer) {
295
+ container.shapeDrawers.set(this.shape, shapeDrawer);
264
296
  }
265
297
  }
266
- if (drawer && drawer.loadShape) {
267
- drawer.loadShape(this);
298
+ if (shapeDrawer && shapeDrawer.loadShape) {
299
+ shapeDrawer.loadShape(this);
268
300
  }
269
- const sideCountFunc = drawer?.getSidesCount;
301
+ const sideCountFunc = shapeDrawer?.getSidesCount;
270
302
  if (sideCountFunc) {
271
303
  this.sides = sideCountFunc(this);
272
304
  }
273
305
  this.spawning = false;
274
306
  this.shadowColor = rangeColorToRgb(this.options.shadow.color);
275
- for (const updater of container.particles.updaters) {
307
+ for (const updater of particles.updaters) {
276
308
  updater.init(this);
277
309
  }
278
- for (const mover of container.particles.movers) {
310
+ for (const mover of particles.movers) {
279
311
  mover.init && mover.init(this);
280
312
  }
281
- if (drawer && drawer.particleInit) {
282
- drawer.particleInit(container, this);
313
+ if (effectDrawer && effectDrawer.particleInit) {
314
+ effectDrawer.particleInit(container, this);
315
+ }
316
+ if (shapeDrawer && shapeDrawer.particleInit) {
317
+ shapeDrawer.particleInit(container, this);
283
318
  }
284
319
  for (const [, plugin] of container.plugins) {
285
320
  plugin.particleCreated && plugin.particleCreated(this);
@@ -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
  }
@@ -0,0 +1 @@
1
+ export {};