@tsparticles/engine 3.4.0 → 3.6.0-beta.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 (51) hide show
  1. package/README.md +0 -2
  2. package/browser/Core/Canvas.js +4 -6
  3. package/browser/Core/Container.js +15 -15
  4. package/browser/Core/Engine.js +1 -1
  5. package/browser/Core/Particle.js +4 -4
  6. package/browser/Core/Particles.js +9 -8
  7. package/browser/Core/Utils/EventListeners.js +1 -1
  8. package/browser/Utils/CanvasUtils.js +2 -2
  9. package/browser/Utils/ColorUtils.js +3 -3
  10. package/browser/Utils/NumberUtils.js +17 -4
  11. package/cjs/Core/Canvas.js +4 -6
  12. package/cjs/Core/Container.js +15 -15
  13. package/cjs/Core/Engine.js +1 -1
  14. package/cjs/Core/Particle.js +4 -4
  15. package/cjs/Core/Particles.js +9 -8
  16. package/cjs/Core/Utils/EventListeners.js +1 -1
  17. package/cjs/Utils/CanvasUtils.js +13 -14
  18. package/cjs/Utils/ColorUtils.js +23 -24
  19. package/cjs/Utils/NumberUtils.js +43 -28
  20. package/cjs/Utils/OptionsUtils.js +2 -3
  21. package/cjs/Utils/TypeUtils.js +6 -7
  22. package/cjs/Utils/Utils.js +29 -30
  23. package/cjs/init.js +1 -2
  24. package/esm/Core/Canvas.js +4 -6
  25. package/esm/Core/Container.js +15 -15
  26. package/esm/Core/Engine.js +1 -1
  27. package/esm/Core/Particle.js +4 -4
  28. package/esm/Core/Particles.js +9 -8
  29. package/esm/Core/Utils/EventListeners.js +1 -1
  30. package/esm/Utils/CanvasUtils.js +2 -2
  31. package/esm/Utils/ColorUtils.js +3 -3
  32. package/esm/Utils/NumberUtils.js +17 -4
  33. package/package.json +1 -1
  34. package/report.html +1 -1
  35. package/tsparticles.engine.js +12 -12
  36. package/tsparticles.engine.min.js +1 -1
  37. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  38. package/types/Utils/NumberUtils.d.ts +3 -0
  39. package/umd/Core/Canvas.js +4 -6
  40. package/umd/Core/Container.js +16 -16
  41. package/umd/Core/Engine.js +1 -1
  42. package/umd/Core/Particle.js +4 -4
  43. package/umd/Core/Particles.js +9 -8
  44. package/umd/Core/Utils/EventListeners.js +1 -1
  45. package/umd/Utils/CanvasUtils.js +13 -14
  46. package/umd/Utils/ColorUtils.js +23 -24
  47. package/umd/Utils/NumberUtils.js +43 -28
  48. package/umd/Utils/OptionsUtils.js +2 -3
  49. package/umd/Utils/TypeUtils.js +6 -7
  50. package/umd/Utils/Utils.js +29 -30
  51. package/umd/init.js +1 -2
@@ -1,6 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateAnimation = exports.getSize = exports.getPosition = exports.initParticleNumericAnimationValue = exports.findItemFromSingleOrMultiple = exports.itemFromSingleOrMultiple = exports.executeOnSingleOrMultiple = exports.rectBounce = exports.circleBounce = exports.circleBounceDataFromParticle = exports.divMode = exports.singleDivModeExecute = exports.divModeExecute = exports.isDivModeEnabled = exports.deepExtend = exports.calculateBounds = exports.areBoundsInside = exports.isPointInside = exports.itemFromArray = exports.arrayRandomIndex = exports.loadFont = exports.isInArray = exports.safeMutationObserver = exports.safeIntersectionObserver = exports.safeMatchMedia = exports.hasMatchMedia = exports.isSsr = exports.getLogger = exports.setLogger = void 0;
3
+ exports.setLogger = setLogger;
4
+ exports.getLogger = getLogger;
5
+ exports.isSsr = isSsr;
6
+ exports.hasMatchMedia = hasMatchMedia;
7
+ exports.safeMatchMedia = safeMatchMedia;
8
+ exports.safeIntersectionObserver = safeIntersectionObserver;
9
+ exports.safeMutationObserver = safeMutationObserver;
10
+ exports.isInArray = isInArray;
11
+ exports.loadFont = loadFont;
12
+ exports.arrayRandomIndex = arrayRandomIndex;
13
+ exports.itemFromArray = itemFromArray;
14
+ exports.isPointInside = isPointInside;
15
+ exports.areBoundsInside = areBoundsInside;
16
+ exports.calculateBounds = calculateBounds;
17
+ exports.deepExtend = deepExtend;
18
+ exports.isDivModeEnabled = isDivModeEnabled;
19
+ exports.divModeExecute = divModeExecute;
20
+ exports.singleDivModeExecute = singleDivModeExecute;
21
+ exports.divMode = divMode;
22
+ exports.circleBounceDataFromParticle = circleBounceDataFromParticle;
23
+ exports.circleBounce = circleBounce;
24
+ exports.rectBounce = rectBounce;
25
+ exports.executeOnSingleOrMultiple = executeOnSingleOrMultiple;
26
+ exports.itemFromSingleOrMultiple = itemFromSingleOrMultiple;
27
+ exports.findItemFromSingleOrMultiple = findItemFromSingleOrMultiple;
28
+ exports.initParticleNumericAnimationValue = initParticleNumericAnimationValue;
29
+ exports.getPosition = getPosition;
30
+ exports.getSize = getSize;
31
+ exports.updateAnimation = updateAnimation;
4
32
  const NumberUtils_js_1 = require("./NumberUtils.js");
5
33
  const Constants_js_1 = require("../Core/Utils/Constants.js");
6
34
  const TypeUtils_js_1 = require("./TypeUtils.js");
@@ -27,11 +55,9 @@ function setLogger(logger) {
27
55
  _logger.verbose = logger.verbose || _logger.verbose;
28
56
  _logger.warning = logger.warning || _logger.warning;
29
57
  }
30
- exports.setLogger = setLogger;
31
58
  function getLogger() {
32
59
  return _logger;
33
60
  }
34
- exports.getLogger = getLogger;
35
61
  function rectSideBounce(data) {
36
62
  const res = { bounced: false }, { pSide, pOtherSide, rectSide, rectOtherSide, velocity, factor } = data, half = 0.5, minVelocity = 0;
37
63
  if (pOtherSide.min < rectOtherSide.min ||
@@ -56,37 +82,31 @@ function checkSelector(element, selectors) {
56
82
  function isSsr() {
57
83
  return typeof window === "undefined" || !window || typeof window.document === "undefined" || !window.document;
58
84
  }
59
- exports.isSsr = isSsr;
60
85
  function hasMatchMedia() {
61
86
  return !isSsr() && typeof matchMedia !== "undefined";
62
87
  }
63
- exports.hasMatchMedia = hasMatchMedia;
64
88
  function safeMatchMedia(query) {
65
89
  if (!hasMatchMedia()) {
66
90
  return;
67
91
  }
68
92
  return matchMedia(query);
69
93
  }
70
- exports.safeMatchMedia = safeMatchMedia;
71
94
  function safeIntersectionObserver(callback) {
72
95
  if (isSsr() || typeof IntersectionObserver === "undefined") {
73
96
  return;
74
97
  }
75
98
  return new IntersectionObserver(callback);
76
99
  }
77
- exports.safeIntersectionObserver = safeIntersectionObserver;
78
100
  function safeMutationObserver(callback) {
79
101
  if (isSsr() || typeof MutationObserver === "undefined") {
80
102
  return;
81
103
  }
82
104
  return new MutationObserver(callback);
83
105
  }
84
- exports.safeMutationObserver = safeMutationObserver;
85
106
  function isInArray(value, array) {
86
107
  const invalidIndex = -1;
87
108
  return value === array || ((0, TypeUtils_js_1.isArray)(array) && array.indexOf(value) > invalidIndex);
88
109
  }
89
- exports.isInArray = isInArray;
90
110
  async function loadFont(font, weight) {
91
111
  try {
92
112
  await document.fonts.load(`${weight ?? "400"} 36px '${font ?? "Verdana"}'`);
@@ -94,20 +114,16 @@ async function loadFont(font, weight) {
94
114
  catch {
95
115
  }
96
116
  }
97
- exports.loadFont = loadFont;
98
117
  function arrayRandomIndex(array) {
99
118
  return Math.floor((0, NumberUtils_js_1.getRandom)() * array.length);
100
119
  }
101
- exports.arrayRandomIndex = arrayRandomIndex;
102
120
  function itemFromArray(array, index, useIndex = true) {
103
121
  return array[index !== undefined && useIndex ? index % array.length : arrayRandomIndex(array)];
104
122
  }
105
- exports.itemFromArray = itemFromArray;
106
123
  function isPointInside(point, size, offset, radius, direction) {
107
124
  const minRadius = 0;
108
125
  return areBoundsInside(calculateBounds(point, radius ?? minRadius), size, offset, direction);
109
126
  }
110
- exports.isPointInside = isPointInside;
111
127
  function areBoundsInside(bounds, size, offset, direction) {
112
128
  let inside = true;
113
129
  if (!direction || direction === OutModeDirection_js_1.OutModeDirection.bottom) {
@@ -124,7 +140,6 @@ function areBoundsInside(bounds, size, offset, direction) {
124
140
  }
125
141
  return inside;
126
142
  }
127
- exports.areBoundsInside = areBoundsInside;
128
143
  function calculateBounds(point, radius) {
129
144
  return {
130
145
  bottom: point.y + radius,
@@ -133,7 +148,6 @@ function calculateBounds(point, radius) {
133
148
  top: point.y - radius,
134
149
  };
135
150
  }
136
- exports.calculateBounds = calculateBounds;
137
151
  function deepExtend(destination, ...sources) {
138
152
  for (const source of sources) {
139
153
  if (source === undefined || source === null) {
@@ -163,11 +177,9 @@ function deepExtend(destination, ...sources) {
163
177
  }
164
178
  return destination;
165
179
  }
166
- exports.deepExtend = deepExtend;
167
180
  function isDivModeEnabled(mode, divs) {
168
181
  return !!findItemFromSingleOrMultiple(divs, t => t.enable && isInArray(mode, t.mode));
169
182
  }
170
- exports.isDivModeEnabled = isDivModeEnabled;
171
183
  function divModeExecute(mode, divs, callback) {
172
184
  executeOnSingleOrMultiple(divs, div => {
173
185
  const divMode = div.mode, divEnabled = div.enable;
@@ -176,14 +188,12 @@ function divModeExecute(mode, divs, callback) {
176
188
  }
177
189
  });
178
190
  }
179
- exports.divModeExecute = divModeExecute;
180
191
  function singleDivModeExecute(div, callback) {
181
192
  const selectors = div.selectors;
182
193
  executeOnSingleOrMultiple(selectors, selector => {
183
194
  callback(selector, div);
184
195
  });
185
196
  }
186
- exports.singleDivModeExecute = singleDivModeExecute;
187
197
  function divMode(divs, element) {
188
198
  if (!element || !divs) {
189
199
  return;
@@ -192,7 +202,6 @@ function divMode(divs, element) {
192
202
  return checkSelector(element, div.selectors);
193
203
  });
194
204
  }
195
- exports.divMode = divMode;
196
205
  function circleBounceDataFromParticle(p) {
197
206
  return {
198
207
  position: p.getPosition(),
@@ -202,7 +211,6 @@ function circleBounceDataFromParticle(p) {
202
211
  factor: Vectors_js_1.Vector.create((0, NumberUtils_js_1.getRangeValue)(p.options.bounce.horizontal.value), (0, NumberUtils_js_1.getRangeValue)(p.options.bounce.vertical.value)),
203
212
  };
204
213
  }
205
- exports.circleBounceDataFromParticle = circleBounceDataFromParticle;
206
214
  function circleBounce(p1, p2) {
207
215
  const { x: xVelocityDiff, y: yVelocityDiff } = p1.velocity.sub(p2.velocity), [pos1, pos2] = [p1.position, p2.position], { dx: xDist, dy: yDist } = (0, NumberUtils_js_1.getDistances)(pos2, pos1), minimumDistance = 0;
208
216
  if (xVelocityDiff * xDist + yVelocityDiff * yDist < minimumDistance) {
@@ -214,7 +222,6 @@ function circleBounce(p1, p2) {
214
222
  p2.velocity.x = vFinal2.x * p2.factor.x;
215
223
  p2.velocity.y = vFinal2.y * p2.factor.y;
216
224
  }
217
- exports.circleBounce = circleBounce;
218
225
  function rectBounce(particle, divBounds) {
219
226
  const pPos = particle.getPosition(), size = particle.getRadius(), bounds = calculateBounds(pPos, size), bounceOptions = particle.options.bounce, resH = rectSideBounce({
220
227
  pSide: {
@@ -273,16 +280,13 @@ function rectBounce(particle, divBounds) {
273
280
  }
274
281
  }
275
282
  }
276
- exports.rectBounce = rectBounce;
277
283
  function executeOnSingleOrMultiple(obj, callback) {
278
284
  const defaultIndex = 0;
279
285
  return (0, TypeUtils_js_1.isArray)(obj) ? obj.map((item, index) => callback(item, index)) : callback(obj, defaultIndex);
280
286
  }
281
- exports.executeOnSingleOrMultiple = executeOnSingleOrMultiple;
282
287
  function itemFromSingleOrMultiple(obj, index, useIndex) {
283
288
  return (0, TypeUtils_js_1.isArray)(obj) ? itemFromArray(obj, index, useIndex) : obj;
284
289
  }
285
- exports.itemFromSingleOrMultiple = itemFromSingleOrMultiple;
286
290
  function findItemFromSingleOrMultiple(obj, callback) {
287
291
  if ((0, TypeUtils_js_1.isArray)(obj)) {
288
292
  return obj.find((t, index) => callback(t, index));
@@ -290,7 +294,6 @@ function findItemFromSingleOrMultiple(obj, callback) {
290
294
  const defaultIndex = 0;
291
295
  return callback(obj, defaultIndex) ? obj : undefined;
292
296
  }
293
- exports.findItemFromSingleOrMultiple = findItemFromSingleOrMultiple;
294
297
  function initParticleNumericAnimationValue(options, pxRatio) {
295
298
  const valueRange = options.value, animationOptions = options.animation, res = {
296
299
  delayTime: (0, NumberUtils_js_1.getRangeValue)(animationOptions.delay) * Constants_js_1.millisecondsToSeconds,
@@ -341,7 +344,6 @@ function initParticleNumericAnimationValue(options, pxRatio) {
341
344
  res.initialValue = res.value;
342
345
  return res;
343
346
  }
344
- exports.initParticleNumericAnimationValue = initParticleNumericAnimationValue;
345
347
  function getPositionOrSize(positionOrSize, canvasSize) {
346
348
  const isPercent = positionOrSize.mode === PixelMode_js_1.PixelMode.percent;
347
349
  if (!isPercent) {
@@ -365,11 +367,9 @@ function getPositionOrSize(positionOrSize, canvasSize) {
365
367
  function getPosition(position, canvasSize) {
366
368
  return getPositionOrSize(position, canvasSize);
367
369
  }
368
- exports.getPosition = getPosition;
369
370
  function getSize(size, canvasSize) {
370
371
  return getPositionOrSize(size, canvasSize);
371
372
  }
372
- exports.getSize = getSize;
373
373
  function checkDestroy(particle, destroyType, value, minValue, maxValue) {
374
374
  switch (destroyType) {
375
375
  case DestroyType_js_1.DestroyType.max:
@@ -445,4 +445,3 @@ function updateAnimation(particle, data, changeDirection, destroyType, delta) {
445
445
  data.value = (0, NumberUtils_js_1.clamp)(data.value, minValue, maxValue);
446
446
  }
447
447
  }
448
- exports.updateAnimation = updateAnimation;
package/cjs/init.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.init = void 0;
3
+ exports.init = init;
4
4
  const Engine_js_1 = require("./Core/Engine.js");
5
5
  const HslColorManager_js_1 = require("./Utils/HslColorManager.js");
6
6
  const RgbColorManager_js_1 = require("./Utils/RgbColorManager.js");
@@ -13,4 +13,3 @@ function init() {
13
13
  engine.init();
14
14
  return engine;
15
15
  }
16
- exports.init = init;
@@ -22,9 +22,6 @@ function setStyle(canvas, style, important = false) {
22
22
  }
23
23
  for (const key in style) {
24
24
  const value = style[key];
25
- if (!value) {
26
- continue;
27
- }
28
25
  elementStyle.setProperty(key, value, important ? "important" : "");
29
26
  }
30
27
  }
@@ -208,10 +205,11 @@ export class Canvas {
208
205
  if (!element) {
209
206
  return;
210
207
  }
211
- const radix = 10;
208
+ const radix = 10, zIndex = this.container.actualOptions.fullScreen.zIndex.toString(radix);
212
209
  setStyle(element, {
213
210
  position: "fixed",
214
- zIndex: this.container.actualOptions.fullScreen.zIndex.toString(radix),
211
+ "z-index": zIndex,
212
+ zIndex: zIndex,
215
213
  top: "0",
216
214
  left: "0",
217
215
  width: "100%",
@@ -378,7 +376,7 @@ export class Canvas {
378
376
  }
379
377
  initPlugins() {
380
378
  this._resizePlugins = [];
381
- for (const [, plugin] of this.container.plugins) {
379
+ for (const plugin of this.container.plugins.values()) {
382
380
  if (plugin.resize) {
383
381
  this._resizePlugins.push(plugin);
384
382
  }
@@ -1,3 +1,4 @@
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";
@@ -6,7 +7,6 @@ import { EventType } from "../Enums/Types/EventType.js";
6
7
  import { Options } from "../Options/Classes/Options.js";
7
8
  import { Particles } from "./Particles.js";
8
9
  import { Retina } from "./Retina.js";
9
- import { getRangeValue } from "../Utils/NumberUtils.js";
10
10
  import { loadOptions } from "../Utils/OptionsUtils.js";
11
11
  function guardCheck(container) {
12
12
  return container && !container.destroyed;
@@ -220,10 +220,10 @@ export class Container {
220
220
  this.clearClickHandlers();
221
221
  this.particles.destroy();
222
222
  this.canvas.destroy();
223
- for (const [, effectDrawer] of this.effectDrawers) {
223
+ for (const effectDrawer of this.effectDrawers.values()) {
224
224
  effectDrawer.destroy?.(this);
225
225
  }
226
- for (const [, shapeDrawer] of this.shapeDrawers) {
226
+ for (const shapeDrawer of this.shapeDrawers.values()) {
227
227
  shapeDrawer.destroy?.(this);
228
228
  }
229
229
  for (const key of this.effectDrawers.keys()) {
@@ -255,10 +255,10 @@ export class Container {
255
255
  }
256
256
  this._nextFrame(timestamp);
257
257
  };
258
- this._drawAnimationFrame = requestAnimationFrame(timestamp => frame(timestamp));
258
+ this._drawAnimationFrame = animate(timestamp => frame(timestamp));
259
259
  }
260
260
  async export(type, options = {}) {
261
- for (const [, plugin] of this.plugins) {
261
+ for (const plugin of this.plugins.values()) {
262
262
  if (!plugin.export) {
263
263
  continue;
264
264
  }
@@ -275,7 +275,7 @@ export class Container {
275
275
  return;
276
276
  }
277
277
  this.particles.handleClickMode(mode);
278
- for (const [, plugin] of this.plugins) {
278
+ for (const plugin of this.plugins.values()) {
279
279
  plugin.handleClickMode?.(mode);
280
280
  }
281
281
  }
@@ -317,19 +317,19 @@ export class Container {
317
317
  const defaultFpsLimit = 120, minFpsLimit = 0;
318
318
  this.fpsLimit = fpsLimit > minFpsLimit ? fpsLimit : defaultFpsLimit;
319
319
  this._smooth = smooth;
320
- for (const [, drawer] of this.effectDrawers) {
320
+ for (const drawer of this.effectDrawers.values()) {
321
321
  await drawer.init?.(this);
322
322
  }
323
- for (const [, drawer] of this.shapeDrawers) {
323
+ for (const drawer of this.shapeDrawers.values()) {
324
324
  await drawer.init?.(this);
325
325
  }
326
- for (const [, plugin] of this.plugins) {
326
+ for (const plugin of this.plugins.values()) {
327
327
  await plugin.init?.();
328
328
  }
329
329
  this._engine.dispatchEvent(EventType.containerInit, { container: this });
330
330
  await this.particles.init();
331
331
  this.particles.setDensity();
332
- for (const [, plugin] of this.plugins) {
332
+ for (const plugin of this.plugins.values()) {
333
333
  plugin.particlesSetup?.();
334
334
  }
335
335
  this._engine.dispatchEvent(EventType.particlesSetup, { container: this });
@@ -346,13 +346,13 @@ export class Container {
346
346
  return;
347
347
  }
348
348
  if (this._drawAnimationFrame !== undefined) {
349
- cancelAnimationFrame(this._drawAnimationFrame);
349
+ cancelAnimation(this._drawAnimationFrame);
350
350
  delete this._drawAnimationFrame;
351
351
  }
352
352
  if (this._paused) {
353
353
  return;
354
354
  }
355
- for (const [, plugin] of this.plugins) {
355
+ for (const plugin of this.plugins.values()) {
356
356
  plugin.pause?.();
357
357
  }
358
358
  if (!this.pageHidden) {
@@ -373,7 +373,7 @@ export class Container {
373
373
  this._paused = false;
374
374
  }
375
375
  if (needsUpdate) {
376
- for (const [, plugin] of this.plugins) {
376
+ for (const plugin of this.plugins.values()) {
377
377
  if (plugin.play) {
378
378
  plugin.play();
379
379
  }
@@ -411,7 +411,7 @@ export class Container {
411
411
  if (this.interactivity.element instanceof HTMLElement && this._intersectionObserver) {
412
412
  this._intersectionObserver.observe(this.interactivity.element);
413
413
  }
414
- for (const [, plugin] of this.plugins) {
414
+ for (const plugin of this.plugins.values()) {
415
415
  await plugin.start?.();
416
416
  }
417
417
  this._engine.dispatchEvent(EventType.containerStarted, { container: this });
@@ -438,7 +438,7 @@ export class Container {
438
438
  if (this.interactivity.element instanceof HTMLElement && this._intersectionObserver) {
439
439
  this._intersectionObserver.unobserve(this.interactivity.element);
440
440
  }
441
- for (const [, plugin] of this.plugins) {
441
+ for (const plugin of this.plugins.values()) {
442
442
  plugin.stop?.();
443
443
  }
444
444
  for (const key of this.plugins.keys()) {
@@ -95,7 +95,7 @@ export class Engine {
95
95
  return this._domArray;
96
96
  }
97
97
  get version() {
98
- return "3.4.0";
98
+ return "3.6.0-beta.0";
99
99
  }
100
100
  addConfig(config) {
101
101
  const key = config.key ?? config.name ?? "default";
@@ -48,7 +48,7 @@ export class Particle {
48
48
  constructor(engine, container) {
49
49
  this.container = container;
50
50
  this._calcPosition = (container, position, zIndex, tryCount = defaultRetryCount) => {
51
- for (const [, plugin] of container.plugins) {
51
+ for (const plugin of container.plugins.values()) {
52
52
  const pluginPos = plugin.particlePosition !== undefined ? plugin.particlePosition(position, this) : undefined;
53
53
  if (pluginPos) {
54
54
  return Vector3d.create(pluginPos.x, pluginPos.y, zIndex);
@@ -166,7 +166,7 @@ export class Particle {
166
166
  this.slow.inRange = false;
167
167
  const container = this.container, pathGenerator = this.pathGenerator, shapeDrawer = container.shapeDrawers.get(this.shape);
168
168
  shapeDrawer?.particleDestroy?.(this);
169
- for (const [, plugin] of container.plugins) {
169
+ for (const plugin of container.plugins.values()) {
170
170
  plugin.particleDestroyed?.(this, override);
171
171
  }
172
172
  for (const updater of container.particles.updaters) {
@@ -182,7 +182,7 @@ export class Particle {
182
182
  }
183
183
  draw(delta) {
184
184
  const container = this.container, canvas = container.canvas;
185
- for (const [, plugin] of container.plugins) {
185
+ for (const plugin of container.plugins.values()) {
186
186
  canvas.drawParticlePlugin(plugin, this, delta);
187
187
  }
188
188
  canvas.drawParticle(this, delta);
@@ -334,7 +334,7 @@ export class Particle {
334
334
  }
335
335
  effectDrawer?.particleInit?.(container, this);
336
336
  shapeDrawer?.particleInit?.(container, this);
337
- for (const [, plugin] of container.plugins) {
337
+ for (const plugin of container.plugins.values()) {
338
338
  plugin.particleCreated?.(this);
339
339
  }
340
340
  }
@@ -122,7 +122,7 @@ export class Particles {
122
122
  options.manualParticles.forEach(p => this.addParticle(p.position ? getPosition(p.position, container.canvas.size) : undefined, p.options));
123
123
  }
124
124
  addParticle(position, overrideOptions, group, initializer) {
125
- const limitMode = this._container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count, minLimit = 0;
125
+ const limitMode = this._container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this._limit : (this._groupLimits.get(group) ?? this._limit), currentCount = this.count, minLimit = 0;
126
126
  if (limit > minLimit) {
127
127
  switch (limitMode) {
128
128
  case LimitMode.delete: {
@@ -156,7 +156,7 @@ export class Particles {
156
156
  const container = this._container, canvas = container.canvas;
157
157
  canvas.clear();
158
158
  this.update(delta);
159
- for (const [, plugin] of container.plugins) {
159
+ for (const plugin of container.plugins.values()) {
160
160
  canvas.drawPlugin(plugin, delta);
161
161
  }
162
162
  for (const p of this._zArray) {
@@ -181,7 +181,7 @@ export class Particles {
181
181
  this._needsSort = false;
182
182
  await this.initPlugins();
183
183
  let handled = false;
184
- for (const [, plugin] of container.plugins) {
184
+ for (const plugin of container.plugins.values()) {
185
185
  handled = plugin.particlesInitialization?.() ?? handled;
186
186
  if (handled) {
187
187
  break;
@@ -209,7 +209,7 @@ export class Particles {
209
209
  this.movers = await this._engine.getMovers(container, true);
210
210
  this.updaters = await this._engine.getUpdaters(container, true);
211
211
  await this._interactionManager.init();
212
- for (const [, pathGenerator] of container.pathGenerators) {
212
+ for (const pathGenerator of container.pathGenerators.values()) {
213
213
  pathGenerator.init(container);
214
214
  }
215
215
  }
@@ -233,7 +233,8 @@ export class Particles {
233
233
  }
234
234
  let deleted = 0;
235
235
  for (let i = index; deleted < quantity && i < this.count; i++) {
236
- if (this._removeParticle(i--, group, override)) {
236
+ if (this._removeParticle(i, group, override)) {
237
+ i--;
237
238
  deleted++;
238
239
  }
239
240
  }
@@ -259,10 +260,10 @@ export class Particles {
259
260
  update(delta) {
260
261
  const container = this._container, particlesToDelete = new Set();
261
262
  this.quadTree = new QuadTree(qTreeRectangle(container.canvas.size), qTreeCapacity);
262
- for (const [, pathGenerator] of container.pathGenerators) {
263
+ for (const pathGenerator of container.pathGenerators.values()) {
263
264
  pathGenerator.update();
264
265
  }
265
- for (const [, plugin] of container.plugins) {
266
+ for (const plugin of container.plugins.values()) {
266
267
  plugin.update?.(delta);
267
268
  }
268
269
  const resizeFactor = this._resizeFactor;
@@ -275,7 +276,7 @@ export class Particles {
275
276
  }
276
277
  particle.ignoresResizeRatio = false;
277
278
  this._interactionManager.reset(particle);
278
- for (const [, plugin] of this._container.plugins) {
279
+ for (const plugin of this._container.plugins.values()) {
279
280
  if (particle.destroyed) {
280
281
  break;
281
282
  }
@@ -187,7 +187,7 @@ export class EventListeners {
187
187
  if (!mousePosition || !options.interactivity.events.onClick.enable) {
188
188
  return;
189
189
  }
190
- for (const [, plugin] of container.plugins) {
190
+ for (const plugin of container.plugins.values()) {
191
191
  if (!plugin.clickPositionValid) {
192
192
  continue;
193
193
  }
@@ -33,8 +33,8 @@ export function drawParticle(data) {
33
33
  cos: Math.cos(angle),
34
34
  }, rotating = !!angle, identity = 1, transformData = {
35
35
  a: rotateData.cos * (transform.a ?? defaultTransform.a),
36
- b: rotating ? rotateData.sin * (transform.b ?? identity) : transform.b ?? defaultTransform.b,
37
- c: rotating ? -rotateData.sin * (transform.c ?? identity) : transform.c ?? defaultTransform.c,
36
+ b: rotating ? rotateData.sin * (transform.b ?? identity) : (transform.b ?? defaultTransform.b),
37
+ c: rotating ? -rotateData.sin * (transform.c ?? identity) : (transform.c ?? defaultTransform.c),
38
38
  d: rotateData.cos * (transform.d ?? defaultTransform.d),
39
39
  };
40
40
  context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
@@ -15,7 +15,7 @@ export function addColorManager(manager) {
15
15
  colorManagers.set(manager.key, manager);
16
16
  }
17
17
  function stringToRgba(input) {
18
- for (const [, manager] of colorManagers) {
18
+ for (const manager of colorManagers.values()) {
19
19
  if (input.startsWith(manager.stringPrefix)) {
20
20
  return manager.parseString(input);
21
21
  }
@@ -47,7 +47,7 @@ export function rangeColorToRgb(input, index, useIndex = true) {
47
47
  value: itemFromArray(color.value, index, useIndex),
48
48
  });
49
49
  }
50
- for (const [, manager] of colorManagers) {
50
+ for (const manager of colorManagers.values()) {
51
51
  const res = manager.handleRangeColor(color);
52
52
  if (res) {
53
53
  return res;
@@ -67,7 +67,7 @@ export function colorToRgb(input, index, useIndex = true) {
67
67
  value: itemFromArray(color.value, index, useIndex),
68
68
  });
69
69
  }
70
- for (const [, manager] of colorManagers) {
70
+ for (const manager of colorManagers.values()) {
71
71
  const res = manager.handleColor(color);
72
72
  if (res) {
73
73
  return res;
@@ -3,15 +3,18 @@ import { Vector } from "../Core/Utils/Vectors.js";
3
3
  import { isNumber } from "./TypeUtils.js";
4
4
  import { percentDenominator } from "../Core/Utils/Constants.js";
5
5
  let _random = Math.random;
6
- const easings = new Map(), double = 2, doublePI = Math.PI * double;
6
+ const _animationLoop = {
7
+ nextFrame: (cb) => requestAnimationFrame(cb),
8
+ cancel: (idx) => cancelAnimationFrame(idx),
9
+ }, easingFunctions = new Map(), double = 2, doublePI = Math.PI * double;
7
10
  export function addEasing(name, easing) {
8
- if (easings.get(name)) {
11
+ if (easingFunctions.get(name)) {
9
12
  return;
10
13
  }
11
- easings.set(name, easing);
14
+ easingFunctions.set(name, easing);
12
15
  }
13
16
  export function getEasing(name) {
14
- return easings.get(name) ?? ((value) => value);
17
+ return easingFunctions.get(name) ?? ((value) => value);
15
18
  }
16
19
  export function setRandom(rnd = Math.random) {
17
20
  _random = rnd;
@@ -20,6 +23,16 @@ export function getRandom() {
20
23
  const min = 0, max = 1;
21
24
  return clamp(_random(), min, max - Number.EPSILON);
22
25
  }
26
+ export function setAnimationFunctions(nextFrame, cancel) {
27
+ _animationLoop.nextFrame = (callback) => nextFrame(callback);
28
+ _animationLoop.cancel = (handle) => cancel(handle);
29
+ }
30
+ export function animate(fn) {
31
+ return _animationLoop.nextFrame(fn);
32
+ }
33
+ export function cancelAnimation(handle) {
34
+ _animationLoop.cancel(handle);
35
+ }
23
36
  export function clamp(num, min, max) {
24
37
  return Math.min(Math.max(num, min), max);
25
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsparticles/engine",
3
- "version": "3.4.0",
3
+ "version": "3.6.0-beta.0",
4
4
  "description": "Easily create highly customizable particle, confetti and fireworks animations and use them as animated backgrounds for your website. Ready to use components available also for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.",
5
5
  "homepage": "https://particles.js.org",
6
6
  "scripts": {
package/report.html CHANGED
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8"/>
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
6
- <title>@tsparticles/engine [13 May 2024 at 00:05]</title>
6
+ <title>@tsparticles/engine [7 Oct 2024 at 10:30]</title>
7
7
  <link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABrVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+O1foceMD///+J0/qK1Pr7/v8Xdr/9///W8P4UdL7L7P0Scr2r4Pyj3vwad8D5/f/2/f+55f3E6f34+/2H0/ojfMKpzOd0rNgQcb3F3O/j9f7c8v6g3Pz0/P/w+v/q+P7n9v6T1/uQ1vuE0vqLut/y+v+Z2fvt+f+15Pzv9fuc2/vR7v2V2Pvd6/bg9P7I6/285/2y4/yp3/zp8vk8i8kqgMT7/P31+fyv4vxGkcz6/P6/6P3j7vfS5PNnpNUxhcbO7f7F6v3O4vHK3/DA2u631Ouy0eqXweKJud5wqthfoNMMbLvY8f73+v2dxeR8sNtTmdDx9/zX6PSjyeaCtd1YnNGX2PuQveCGt95Nls42h8dLlM3F4vBtAAAAM3RSTlMAAyOx0/sKBvik8opWGBMOAe3l1snDm2E9LSb06eHcu5JpHbarfHZCN9CBb08zzkdNS0kYaptYAAAFV0lEQVRYw92X51/aYBDHHS2O2qqttVbrqNq9m+TJIAYIShBkWwqIiCgoWvfeq7Z2/s29hyQNyUcR7LveGwVyXy6XH8/9rqxglLfUPLxVduUor3h0rfp2TYvpivk37929TkG037hffoX0+peVtZQc1589rigVUdXS/ABSAyEmGIO/1XfvldSK8vs3OqB6u3m0nxmIrvgB0dj7rr7Y9IbuF68hnfFaiHA/sxqm0wciIG43P60qKv9WXWc1RXGh/mFESFABTSBi0sNAKzqet17eCtOb3kZIDwxEEU0oAIJGYxNBDhBND29e0rtXXbcpuPmED9IhEAAQ/AXEaF8EPmnrrKsv0LvWR3fg5sWDNAFZOgAgaKvZDogHNU9MFwnnYROkc56RD5CjAbQX9Ow4g7upCsvYu55aSI/Nj0H1akgKQEUM94dwK65hYRmFU9MIcH/fqJYOZYcnuJSU/waKDgTOEVaVKhwrTRP5XzgSpAITYzom7UvkhFX5VutmxeNnWDjjswTKTyfgluNDGbUpWissXhF3s7mlSml+czWkg3D0l1nNjGNjz3myOQOa1KM/jOS6ebdbAVTCi4gljHSFrviza7tOgRWcS0MOUX9zdNgag5w7rRqA44Lzw0hr1WqES36dFliSJFlh2rXIae3FFcDDgKdxrUIDePr8jGcSClV1u7A9xeN0ModY/pHMxmR1EzRh8TJiwqsHmKW0l4FCEZI+jHio+JdPPE9qwQtTRxku2D8sIeRL2LnxWSllANCQGOIiqVHAz2ye2JR0DcH+HoxDkaADLjgxjKQ+AwCX/g0+DNgdG0ukYCONAe+dbc2IAc6fwt1ARoDSezNHxV2Cmzwv3O6lDMV55edBGwGK9n1+x2F8EDfAGCxug8MhpsMEcTEAWf3rx2vZhe/LAmtIn/6apE6PN0ULKgywD9mmdxbmFl3OvD5AS5fW5zLbv/YHmcsBTjf/afDz3MaZTVCfAP9z6/Bw6ycv8EUBWJIn9zYcoAWWlW9+OzO3vkTy8H+RANLmdrpOuYWdZYEXpo+TlCJrW5EARb7fF+bWdqf3hhyZI1nWJQHgznErZhbjoEsWqi8dQNoE294aldzFurwSABL2XXMf9+H1VQGke9exw5P/AnA5Pv5ngMul7LOvO922iwACu8WkCwLCafvM4CeWPxfA8lNHcWZSoi8EwMAIciKX2Z4SWCMAa3snCZ/G4EA8D6CMLNFsGQhkkz/gQNEBbPCbWsxGUpYVu3z8IyNAknwJkfPMEhLyrdi5RTyUVACkw4GSFRNWJNEW+fgPGwHD8/JxnRuLabN4CGNRkAE23na2+VmEAUmrYymSGjMAYqH84YUIyzgzs3XC7gNgH36Vcc4zKY9o9fgPBXUAiHHwVboBHGLiX6Zcjp1f2wu4tvzZKo0ecPnDtQYDQvJXaBeNzce45Fp28ZQLrEZVuFqgBwOalArKXnW1UzlnSusQKJqKYNuz4tOnI6sZG4zanpemv+7ySU2jbA9h6uhcgpfy6G2PahirDZ6zvq6zDduMVFTKvzw8wgyEdelwY9in3XkEPs3osJuwRQ4qTkfzifndg9Gfc4pdsu82+tTnHZTBa2EAMrqr2t43pguc8tNm7JQVQ2S0ukj2d22dhXYP0/veWtwKrCkNoNimAN5+Xr/oLrxswKbVJjteWrX7eR63o4j9q0GxnaBdWgGA5VStpanIjQmEhV0/nVt5VOFUvix6awJhPcAaTEShgrG+iGyvb5a0Ndb1YGHFPEwoqAinoaykaID1o1pdPNu7XsnCKQ3R+hwWIIhGvORcJUBYXe3Xa3vq/mF/N9V13ugufMkfXn+KHsRD0B8AAAAASUVORK5CYII=" type="image/x-icon" />
8
8
 
9
9
  <script>