@tsparticles/engine 4.0.0-alpha.24 → 4.0.0-alpha.26

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 (100) hide show
  1. package/622.min.js +1 -0
  2. package/README.md +2 -2
  3. package/browser/Core/Engine.js +1 -18
  4. package/browser/Core/Particle.js +2 -23
  5. package/browser/Core/Particles.js +8 -37
  6. package/browser/Core/Utils/Constants.js +1 -1
  7. package/browser/Core/Utils/Ranges.js +2 -2
  8. package/browser/Core/Utils/SpatialHashGrid.js +82 -0
  9. package/browser/Core/Utils/Vectors.js +12 -16
  10. package/browser/Options/Classes/Particles/Move/Move.js +0 -4
  11. package/browser/Utils/CanvasUtils.js +29 -32
  12. package/browser/Utils/MathUtils.js +8 -1
  13. package/browser/Utils/Utils.js +10 -14
  14. package/browser/exports.js +0 -2
  15. package/cjs/Core/Engine.js +1 -18
  16. package/cjs/Core/Particle.js +2 -23
  17. package/cjs/Core/Particles.js +8 -37
  18. package/cjs/Core/Utils/Constants.js +1 -1
  19. package/cjs/Core/Utils/Ranges.js +2 -2
  20. package/cjs/Core/Utils/SpatialHashGrid.js +82 -0
  21. package/cjs/Core/Utils/Vectors.js +12 -16
  22. package/cjs/Options/Classes/Particles/Move/Move.js +0 -4
  23. package/cjs/Utils/CanvasUtils.js +29 -32
  24. package/cjs/Utils/MathUtils.js +8 -1
  25. package/cjs/Utils/Utils.js +10 -14
  26. package/cjs/exports.js +0 -2
  27. package/dist_browser_Core_Container_js.js +8 -8
  28. package/esm/Core/Engine.js +1 -18
  29. package/esm/Core/Particle.js +2 -23
  30. package/esm/Core/Particles.js +8 -37
  31. package/esm/Core/Utils/Constants.js +1 -1
  32. package/esm/Core/Utils/Ranges.js +2 -2
  33. package/esm/Core/Utils/SpatialHashGrid.js +82 -0
  34. package/esm/Core/Utils/Vectors.js +12 -16
  35. package/esm/Options/Classes/Particles/Move/Move.js +0 -4
  36. package/esm/Utils/CanvasUtils.js +29 -32
  37. package/esm/Utils/MathUtils.js +8 -1
  38. package/esm/Utils/Utils.js +10 -14
  39. package/esm/exports.js +0 -2
  40. package/package.json +1 -1
  41. package/report.html +1 -1
  42. package/scripts/install.js +2 -2
  43. package/tsparticles.engine.js +11 -31
  44. package/tsparticles.engine.min.js +2 -2
  45. package/types/Core/Engine.d.ts +1 -9
  46. package/types/Core/Particle.d.ts +0 -4
  47. package/types/Core/Particles.d.ts +2 -7
  48. package/types/Core/Utils/Constants.d.ts +1 -1
  49. package/types/Core/Utils/SpatialHashGrid.d.ts +18 -0
  50. package/types/Core/Utils/Vectors.d.ts +8 -10
  51. package/types/Options/Classes/Particles/Move/Move.d.ts +0 -2
  52. package/types/Options/Interfaces/Particles/Move/IMove.d.ts +0 -2
  53. package/types/Types/EngineInitializers.d.ts +0 -6
  54. package/types/Utils/CanvasUtils.d.ts +6 -7
  55. package/types/Utils/MathUtils.d.ts +2 -0
  56. package/types/export-types.d.ts +1 -4
  57. package/types/exports.d.ts +0 -2
  58. package/umd/Core/Engine.js +1 -18
  59. package/umd/Core/Particle.js +3 -24
  60. package/umd/Core/Particles.js +8 -37
  61. package/umd/Core/Utils/Constants.js +2 -2
  62. package/umd/Core/Utils/Ranges.js +1 -1
  63. package/umd/Core/Utils/SpatialHashGrid.js +96 -0
  64. package/umd/Core/Utils/Vectors.js +12 -16
  65. package/umd/Options/Classes/Particles/Move/Move.js +1 -5
  66. package/umd/Utils/CanvasUtils.js +29 -32
  67. package/umd/Utils/MathUtils.js +10 -1
  68. package/umd/Utils/Utils.js +10 -14
  69. package/umd/exports.js +1 -3
  70. package/515.min.js +0 -1
  71. package/browser/Core/Interfaces/IMovePathGenerator.js +0 -1
  72. package/browser/Core/Interfaces/IParticleMover.js +0 -1
  73. package/browser/Core/Utils/Point.js +0 -8
  74. package/browser/Core/Utils/QuadTree.js +0 -85
  75. package/browser/Options/Classes/Particles/Move/MoveAttract.js +0 -36
  76. package/browser/Options/Interfaces/Particles/Move/IMoveAttract.js +0 -1
  77. package/cjs/Core/Interfaces/IMovePathGenerator.js +0 -1
  78. package/cjs/Core/Interfaces/IParticleMover.js +0 -1
  79. package/cjs/Core/Utils/Point.js +0 -8
  80. package/cjs/Core/Utils/QuadTree.js +0 -85
  81. package/cjs/Options/Classes/Particles/Move/MoveAttract.js +0 -36
  82. package/cjs/Options/Interfaces/Particles/Move/IMoveAttract.js +0 -1
  83. package/esm/Core/Interfaces/IMovePathGenerator.js +0 -1
  84. package/esm/Core/Interfaces/IParticleMover.js +0 -1
  85. package/esm/Core/Utils/Point.js +0 -8
  86. package/esm/Core/Utils/QuadTree.js +0 -85
  87. package/esm/Options/Classes/Particles/Move/MoveAttract.js +0 -36
  88. package/esm/Options/Interfaces/Particles/Move/IMoveAttract.js +0 -1
  89. package/types/Core/Interfaces/IMovePathGenerator.d.ts +0 -9
  90. package/types/Core/Interfaces/IParticleMover.d.ts +0 -7
  91. package/types/Core/Utils/Point.d.ts +0 -7
  92. package/types/Core/Utils/QuadTree.d.ts +0 -17
  93. package/types/Options/Classes/Particles/Move/MoveAttract.d.ts +0 -12
  94. package/types/Options/Interfaces/Particles/Move/IMoveAttract.d.ts +0 -7
  95. package/umd/Core/Interfaces/IMovePathGenerator.js +0 -12
  96. package/umd/Core/Interfaces/IParticleMover.js +0 -12
  97. package/umd/Core/Utils/Point.js +0 -22
  98. package/umd/Core/Utils/QuadTree.js +0 -99
  99. package/umd/Options/Classes/Particles/Move/MoveAttract.js +0 -50
  100. package/umd/Options/Interfaces/Particles/Move/IMoveAttract.js +0 -12
@@ -69,8 +69,15 @@ export function getDistances(pointA, pointB) {
69
69
  const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y;
70
70
  return { dx: dx, dy: dy, distance: Math.hypot(dx, dy) };
71
71
  }
72
+ export function getDistanceSq(pointA, pointB) {
73
+ const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y;
74
+ return dx * dx + dy * dy;
75
+ }
72
76
  export function getDistance(pointA, pointB) {
73
- return getDistances(pointA, pointB).distance;
77
+ return Math.sqrt(getDistanceSq(pointA, pointB));
78
+ }
79
+ export function checkDistance(pointA, pointB, distance) {
80
+ return getDistanceSq(pointA, pointB) <= distance * distance;
74
81
  }
75
82
  export function degToRad(degrees) {
76
83
  return degrees * degToRadFactor;
@@ -83,33 +83,29 @@ export function calculateBounds(point, radius) {
83
83
  }
84
84
  export function deepExtend(destination, ...sources) {
85
85
  for (const source of sources) {
86
- if (source === undefined || source === null) {
86
+ if (isNull(source)) {
87
87
  continue;
88
88
  }
89
89
  if (!isObject(source)) {
90
90
  destination = source;
91
91
  continue;
92
92
  }
93
- const sourceIsArray = Array.isArray(source);
94
- if (sourceIsArray) {
93
+ if (Array.isArray(source)) {
95
94
  if (!Array.isArray(destination)) {
96
95
  destination = [];
97
96
  }
98
97
  }
99
- else {
100
- if (!isObject(destination) || Array.isArray(destination)) {
101
- destination = {};
102
- }
98
+ else if (!isObject(destination) || Array.isArray(destination)) {
99
+ destination = {};
103
100
  }
104
- for (const key in source) {
105
- if (key === "__proto__") {
101
+ for (const key of Object.keys(source)) {
102
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
106
103
  continue;
107
104
  }
108
- const sourceDict = source, value = sourceDict[key], destDict = destination;
109
- destDict[key] =
110
- isObject(value) && Array.isArray(value)
111
- ? value.map(v => deepExtend(destDict[key], v))
112
- : deepExtend(destDict[key], value);
105
+ const sourceDict = source, destDict = destination, value = sourceDict[key];
106
+ destDict[key] = Array.isArray(value)
107
+ ? value.map(v => deepExtend(undefined, v))
108
+ : deepExtend(destDict[key], value);
113
109
  }
114
110
  }
115
111
  return destination;
@@ -1,5 +1,4 @@
1
1
  export * from "./Core/Utils/Constants.js";
2
- export * from "./Core/Utils/Point.js";
3
2
  export * from "./Core/Utils/Ranges.js";
4
3
  export * from "./Core/Utils/Vectors.js";
5
4
  export * from "./Enums/Directions/MoveDirection.js";
@@ -29,7 +28,6 @@ export * from "./Options/Classes/Particles/Bounce/ParticlesBounce.js";
29
28
  export * from "./Options/Classes/Particles/Bounce/ParticlesBounceFactor.js";
30
29
  export * from "./Options/Classes/Particles/ParticlesOptions.js";
31
30
  export * from "./Options/Classes/Particles/Stroke.js";
32
- export * from "./Options/Classes/Particles/Move/MoveAttract.js";
33
31
  export * from "./Options/Classes/Particles/Move/Move.js";
34
32
  export * from "./Options/Classes/Particles/Move/MoveAngle.js";
35
33
  export * from "./Options/Classes/Particles/Move/MoveCenter.js";
@@ -57,13 +57,9 @@ export class Engine {
57
57
  effectDrawers = new Map();
58
58
  initializers = {
59
59
  effects: new Map(),
60
- movers: new Map(),
61
- pathGenerators: new Map(),
62
60
  shapes: new Map(),
63
61
  updaters: new Map(),
64
62
  };
65
- movers = new Map();
66
- pathGenerators = new Map();
67
63
  plugins = [];
68
64
  presets = new Map();
69
65
  shapeDrawers = new Map();
@@ -87,7 +83,7 @@ export class Engine {
87
83
  return this._domArray;
88
84
  }
89
85
  get version() {
90
- return "4.0.0-alpha.24";
86
+ return "4.0.0-alpha.26";
91
87
  }
92
88
  addColorManager(name, manager) {
93
89
  this.colorManagers.set(name, manager);
@@ -109,15 +105,9 @@ export class Engine {
109
105
  addEventListener(type, listener) {
110
106
  this._eventDispatcher.addEventListener(type, listener);
111
107
  }
112
- addMover(name, moverInitializer) {
113
- this.initializers.movers.set(name, moverInitializer);
114
- }
115
108
  addParticleUpdater(name, updaterInitializer) {
116
109
  this.initializers.updaters.set(name, updaterInitializer);
117
110
  }
118
- addPathGenerator(name, generator) {
119
- this.initializers.pathGenerators.set(name, generator);
120
- }
121
111
  addPlugin(plugin) {
122
112
  if (this.getPlugin(plugin.id)) {
123
113
  return;
@@ -143,7 +133,6 @@ export class Engine {
143
133
  }
144
134
  clearPlugins(container) {
145
135
  this.effectDrawers.delete(container);
146
- this.movers.delete(container);
147
136
  this.shapeDrawers.delete(container);
148
137
  this.updaters.delete(container);
149
138
  }
@@ -156,12 +145,6 @@ export class Engine {
156
145
  getEffectDrawers(container, force = false) {
157
146
  return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
158
147
  }
159
- getMovers(container, force = false) {
160
- return getItemsFromInitializer(container, this.movers, this.initializers.movers, force);
161
- }
162
- getPathGenerators(container, force = false) {
163
- return getItemMapFromInitializer(container, this.pathGenerators, this.initializers.pathGenerators, force);
164
- }
165
148
  getPlugin(plugin) {
166
149
  return this.plugins.find(t => t.id === plugin);
167
150
  }
@@ -1,8 +1,8 @@
1
1
  import { Vector, Vector3d } from "./Utils/Vectors.js";
2
2
  import { alterHsl, getHslFromAnimation } from "../Utils/ColorUtils.js";
3
3
  import { calcExactPositionOrRandomFromSize, clamp, degToRad, getParticleBaseVelocity, getParticleDirectionAngle, getRandom, getRangeValue, randomInRangeValue, setRangeValue, } from "../Utils/MathUtils.js";
4
- import { decayOffset, defaultAngle, defaultOpacity, defaultRetryCount, defaultTransform, double, doublePI, half, identity, millisecondsToSeconds, minZ, randomColorValue, squareExp, triple, tryCountIncrement, zIndexFactorOffset, } from "./Utils/Constants.js";
5
4
  import { deepExtend, getPosition, initParticleNumericAnimationValue, isInArray, itemFromSingleOrMultiple, } from "../Utils/Utils.js";
5
+ import { defaultAngle, defaultOpacity, defaultRetryCount, defaultTransform, double, doublePI, half, identity, minZ, randomColorValue, squareExp, triple, tryCountIncrement, zIndexFactorOffset, } from "./Utils/Constants.js";
6
6
  import { EventType } from "../Enums/Types/EventType.js";
7
7
  import { MoveDirection } from "../Enums/Directions/MoveDirection.js";
8
8
  import { OutMode } from "../Enums/Modes/OutMode.js";
@@ -54,13 +54,10 @@ export class Particle {
54
54
  lastPathTime;
55
55
  misplaced;
56
56
  moveCenter;
57
- moveDecay;
58
57
  offset;
59
58
  opacity;
60
59
  options;
61
60
  outType;
62
- pathDelay;
63
- pathGenerator;
64
61
  pathRotation;
65
62
  position;
66
63
  randomIndexData;
@@ -105,7 +102,7 @@ export class Particle {
105
102
  this.destroyed = true;
106
103
  this.bubble.inRange = false;
107
104
  this.slow.inRange = false;
108
- const container = this.container, pathGenerator = this.pathGenerator, shapeDrawer = this.shape ? container.particles.shapeDrawers.get(this.shape) : undefined;
105
+ const container = this.container, shapeDrawer = this.shape ? container.particles.shapeDrawers.get(this.shape) : undefined;
109
106
  shapeDrawer?.particleDestroy?.(this);
110
107
  for (const plugin of container.particleDestroyedPlugins) {
111
108
  plugin.particleDestroyed?.(this, override);
@@ -113,7 +110,6 @@ export class Particle {
113
110
  for (const updater of container.particles.updaters) {
114
111
  updater.particleDestroyed?.(this, override);
115
112
  }
116
- pathGenerator?.reset(this);
117
113
  this._engine.dispatchEvent(EventType.particleDestroyed, {
118
114
  container: this.container,
119
115
  data: {
@@ -235,19 +231,6 @@ export class Particle {
235
231
  this.shapeFill = shapeData?.fill ?? particlesOptions.shape.fill;
236
232
  this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
237
233
  this.options = particlesOptions;
238
- const pathOptions = this.options.move.path;
239
- this.pathDelay = getRangeValue(pathOptions.delay.value) * millisecondsToSeconds;
240
- if (pathOptions.generator) {
241
- let pathGenerator = this.container.particles.pathGenerators.get(pathOptions.generator);
242
- if (!pathGenerator) {
243
- pathGenerator = this.container.particles.availablePathGenerators.get(pathOptions.generator);
244
- if (pathGenerator) {
245
- this.container.particles.pathGenerators.set(pathOptions.generator, pathGenerator);
246
- pathGenerator.init();
247
- }
248
- }
249
- this.pathGenerator = pathGenerator;
250
- }
251
234
  container.retina.initParticle(this);
252
235
  this.size = initParticleNumericAnimationValue(this.options.size, pxRatio);
253
236
  this.bubble = {
@@ -260,7 +243,6 @@ export class Particle {
260
243
  this._initPosition(position);
261
244
  this.initialVelocity = this._calculateVelocity();
262
245
  this.velocity = this.initialVelocity.copy();
263
- this.moveDecay = decayOffset - getRangeValue(this.options.move.decay);
264
246
  const particles = container.particles;
265
247
  particles.setLastZIndex(this.position.z);
266
248
  this.zIndexFactor = this.position.z / container.zLayers;
@@ -286,9 +268,6 @@ export class Particle {
286
268
  for (const updater of particles.updaters) {
287
269
  updater.init(this);
288
270
  }
289
- for (const mover of particles.movers) {
290
- mover.init(this);
291
- }
292
271
  effectDrawer?.particleInit?.(container, this);
293
272
  shapeDrawer?.particleInit?.(container, this);
294
273
  for (const plugin of container.particleCreatedPlugins) {
@@ -1,23 +1,14 @@
1
- import { countOffset, defaultDensityFactor, defaultRemoveQuantity, deleteCount, lengthOffset, minCount, minIndex, minLimit, posOffset, qTreeCapacity, sizeFactor, squareExp, } from "./Utils/Constants.js";
1
+ import { countOffset, defaultDensityFactor, defaultRemoveQuantity, deleteCount, lengthOffset, minCount, minIndex, minLimit, spatialHashGridCellSize, squareExp, } from "./Utils/Constants.js";
2
2
  import { EventType } from "../Enums/Types/EventType.js";
3
3
  import { LimitMode } from "../Enums/Modes/LimitMode.js";
4
4
  import { Particle } from "./Particle.js";
5
- import { Point } from "./Utils/Point.js";
6
- import { QuadTree } from "./Utils/QuadTree.js";
7
- import { Rectangle } from "./Utils/Ranges.js";
5
+ import { SpatialHashGrid } from "./Utils/SpatialHashGrid.js";
8
6
  import { getLogger } from "../Utils/LogUtils.js";
9
7
  import { loadParticlesOptions } from "../Utils/OptionsUtils.js";
10
- const qTreeRectangle = (canvasSize) => {
11
- const { height, width } = canvasSize;
12
- return new Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
13
- };
14
8
  export class Particles {
15
- availablePathGenerators;
16
9
  checkParticlePositionPlugins;
17
10
  effectDrawers;
18
- movers;
19
- pathGenerators;
20
- quadTree;
11
+ grid;
21
12
  shapeDrawers;
22
13
  updaters;
23
14
  _array;
@@ -49,12 +40,8 @@ export class Particles {
49
40
  this._needsSort = false;
50
41
  this._minZIndex = 0;
51
42
  this._maxZIndex = 0;
52
- const canvasSize = container.canvas.size;
53
- this.quadTree = new QuadTree(qTreeRectangle(canvasSize), qTreeCapacity);
43
+ this.grid = new SpatialHashGrid(spatialHashGridCellSize);
54
44
  this.effectDrawers = new Map();
55
- this.movers = [];
56
- this.availablePathGenerators = new Map();
57
- this.pathGenerators = new Map();
58
45
  this.shapeDrawers = new Map();
59
46
  this.updaters = [];
60
47
  this.checkParticlePositionPlugins = [];
@@ -130,9 +117,6 @@ export class Particles {
130
117
  this._pool.length = 0;
131
118
  this._zArray = [];
132
119
  this.effectDrawers = new Map();
133
- this.movers = [];
134
- this.availablePathGenerators = new Map();
135
- this.pathGenerators = new Map();
136
120
  this.shapeDrawers = new Map();
137
121
  this.updaters = [];
138
122
  this.checkParticlePositionPlugins = [];
@@ -167,6 +151,7 @@ export class Particles {
167
151
  this._postUpdatePlugins = [];
168
152
  this._particleResetPlugins = [];
169
153
  this._postParticleUpdatePlugins = [];
154
+ this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
170
155
  for (const plugin of container.plugins) {
171
156
  if (plugin.redrawInit) {
172
157
  await plugin.redrawInit();
@@ -223,14 +208,8 @@ export class Particles {
223
208
  async initPlugins() {
224
209
  const container = this._container;
225
210
  this.effectDrawers = await this._engine.getEffectDrawers(container, true);
226
- this.movers = await this._engine.getMovers(container, true);
227
- this.availablePathGenerators = await this._engine.getPathGenerators(container, true);
228
- this.pathGenerators = new Map();
229
211
  this.shapeDrawers = await this._engine.getShapeDrawers(container, true);
230
212
  this.updaters = await this._engine.getUpdaters(container, true);
231
- for (const pathGenerator of this.pathGenerators.values()) {
232
- pathGenerator.init();
233
- }
234
213
  }
235
214
  push(nb, position, overrideOptions, group) {
236
215
  for (let i = 0; i < nb; i++) {
@@ -285,11 +264,8 @@ export class Particles {
285
264
  this._resizeFactor = factor;
286
265
  }
287
266
  update(delta) {
288
- const container = this._container, particlesToDelete = new Set();
289
- this.quadTree = new QuadTree(qTreeRectangle(container.canvas.size), qTreeCapacity);
290
- for (const pathGenerator of this.pathGenerators.values()) {
291
- pathGenerator.update();
292
- }
267
+ const particlesToDelete = new Set();
268
+ this.grid.clear();
293
269
  for (const plugin of this._updatePlugins) {
294
270
  plugin.update?.(delta);
295
271
  }
@@ -311,16 +287,11 @@ export class Particles {
311
287
  }
312
288
  plugin.particleUpdate?.(particle, delta);
313
289
  }
314
- for (const mover of this.movers) {
315
- if (mover.isEnabled(particle)) {
316
- mover.move(particle, delta);
317
- }
318
- }
319
290
  if (particle.destroyed) {
320
291
  particlesToDelete.add(particle);
321
292
  continue;
322
293
  }
323
- this.quadTree.insert(new Point(particle.getPosition(), particle));
294
+ this.grid.insert(particle);
324
295
  }
325
296
  if (particlesToDelete.size) {
326
297
  const checkDelete = (p) => !particlesToDelete.has(p);
@@ -7,4 +7,4 @@ export const generatedAttribute = "generated", resizeEvent = "resize", visibilit
7
7
  b: 0,
8
8
  c: 0,
9
9
  d: 1,
10
- }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, qTreeCapacity = 4, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, subdivideCount = 4, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, defaultTransformValue = 1, minimumSize = 0, minimumLength = 0, zIndexFactorOffset = 1, defaultOpacity = 1, clickRadius = 1, touchEndLengthOffset = 1, minCoordinate = 0, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minRetries = 0, minZ = 0, defaultRadius = 0, posOffset = -quarter, sizeFactor = 1.5, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, touchDelay = 500, manualDefaultPosition = 50, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
10
+ }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, qTreeCapacity = 4, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, subdivideCount = 4, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, defaultTransformValue = 1, minimumSize = 0, minimumLength = 0, zIndexFactorOffset = 1, defaultOpacity = 1, clickRadius = 1, touchEndLengthOffset = 1, minCoordinate = 0, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minRetries = 0, minZ = 0, defaultRadius = 0, posOffset = -quarter, sizeFactor = 1.5, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, touchDelay = 500, manualDefaultPosition = 50, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
@@ -1,5 +1,5 @@
1
1
  import { RangeType } from "../../Enums/RangeType.js";
2
- import { getDistance } from "../../Utils/MathUtils.js";
2
+ import { checkDistance } from "../../Utils/MathUtils.js";
3
3
  import { squareExp } from "./Constants.js";
4
4
  export class BaseRange {
5
5
  position;
@@ -19,7 +19,7 @@ export class Circle extends BaseRange {
19
19
  this.radius = radius;
20
20
  }
21
21
  contains(point) {
22
- return getDistance(point, this.position) <= this.radius;
22
+ return checkDistance(point, this.position, this.radius);
23
23
  }
24
24
  intersects(range) {
25
25
  const pos1 = this.position, pos2 = range.position, distPos = { x: Math.abs(pos2.x - pos1.x), y: Math.abs(pos2.y - pos1.y) }, r = this.radius;
@@ -0,0 +1,82 @@
1
+ import { Circle, Rectangle } from "./Ranges.js";
2
+ export class SpatialHashGrid {
3
+ _cellSize;
4
+ _cells = new Map();
5
+ _pendingCellSize;
6
+ constructor(cellSize) {
7
+ this._cellSize = cellSize;
8
+ }
9
+ clear() {
10
+ this._cells.clear();
11
+ const pendingCellSize = this._pendingCellSize;
12
+ if (pendingCellSize) {
13
+ this._cellSize = pendingCellSize;
14
+ }
15
+ this._pendingCellSize = undefined;
16
+ }
17
+ insert(particle) {
18
+ const { x, y } = particle.getPosition(), key = this._cellKeyFromCoords(x, y);
19
+ if (!this._cells.has(key)) {
20
+ this._cells.set(key, []);
21
+ }
22
+ this._cells.get(key)?.push(particle);
23
+ }
24
+ query(range, check, out = []) {
25
+ const bounds = this._getRangeBounds(range);
26
+ if (!bounds) {
27
+ return out;
28
+ }
29
+ const minCellX = Math.floor(bounds.minX / this._cellSize), maxCellX = Math.floor(bounds.maxX / this._cellSize), minCellY = Math.floor(bounds.minY / this._cellSize), maxCellY = Math.floor(bounds.maxY / this._cellSize);
30
+ for (let cx = minCellX; cx <= maxCellX; cx++) {
31
+ for (let cy = minCellY; cy <= maxCellY; cy++) {
32
+ const key = `${cx}_${cy}`, cellParticles = this._cells.get(key);
33
+ if (!cellParticles) {
34
+ continue;
35
+ }
36
+ for (const p of cellParticles) {
37
+ if (check && !check(p)) {
38
+ continue;
39
+ }
40
+ if (range.contains(p.getPosition())) {
41
+ out.push(p);
42
+ }
43
+ }
44
+ }
45
+ }
46
+ return out;
47
+ }
48
+ queryCircle(position, radius, check, out = []) {
49
+ return this.query(new Circle(position.x, position.y, radius), check, out);
50
+ }
51
+ queryRectangle(position, size, check, out = []) {
52
+ return this.query(new Rectangle(position.x, position.y, size.width, size.height), check, out);
53
+ }
54
+ setCellSize(cellSize) {
55
+ this._pendingCellSize = cellSize;
56
+ }
57
+ _cellKeyFromCoords(x, y) {
58
+ const cellX = Math.floor(x / this._cellSize), cellY = Math.floor(y / this._cellSize);
59
+ return `${cellX}_${cellY}`;
60
+ }
61
+ _getRangeBounds(range) {
62
+ if (range instanceof Circle) {
63
+ const r = range.radius, { x, y } = range.position;
64
+ return {
65
+ minX: x - r,
66
+ maxX: x + r,
67
+ minY: y - r,
68
+ maxY: y + r,
69
+ };
70
+ }
71
+ if (range instanceof Rectangle) {
72
+ const { x, y } = range.position, { width, height } = range.size;
73
+ return {
74
+ minX: x,
75
+ maxX: x + width,
76
+ minY: y,
77
+ maxY: y + height,
78
+ };
79
+ }
80
+ return null;
81
+ }
82
+ }
@@ -1,4 +1,7 @@
1
1
  import { inverseFactorNumerator, none, originPoint, squareExp } from "./Constants.js";
2
+ function getZ(source) {
3
+ return "z" in source ? source.z : originPoint.z;
4
+ }
2
5
  export class Vector3d {
3
6
  x;
4
7
  y;
@@ -24,31 +27,25 @@ export class Vector3d {
24
27
  this._updateFromAngle(this.angle, length);
25
28
  }
26
29
  static clone(source) {
27
- return Vector3d.create(source.x, source.y, source.z);
30
+ return Vector3d.create(source.x, source.y, getZ(source));
28
31
  }
29
32
  static create(x, y, z) {
30
33
  if (typeof x === "number") {
31
34
  return new Vector3d(x, y ?? originPoint.y, z ?? originPoint.z);
32
35
  }
33
- return new Vector3d(x.x, x.y, Object.hasOwn(x, "z") ? x.z : originPoint.z);
36
+ return new Vector3d(x.x, x.y, getZ(x));
34
37
  }
35
38
  add(v) {
36
- return Vector3d.create(this.x + v.x, this.y + v.y, this.z + v.z);
39
+ return Vector3d.create(this.x + v.x, this.y + v.y, this.z + getZ(v));
37
40
  }
38
41
  addTo(v) {
39
42
  this.x += v.x;
40
43
  this.y += v.y;
41
- this.z += v.z;
44
+ this.z += getZ(v);
42
45
  }
43
46
  copy() {
44
47
  return Vector3d.clone(this);
45
48
  }
46
- distanceTo(v) {
47
- return this.sub(v).length;
48
- }
49
- distanceToSq(v) {
50
- return this.sub(v).getLengthSq();
51
- }
52
49
  div(n) {
53
50
  return Vector3d.create(this.x / n, this.y / n, this.z / n);
54
51
  }
@@ -80,21 +77,20 @@ export class Vector3d {
80
77
  setTo(c) {
81
78
  this.x = c.x;
82
79
  this.y = c.y;
83
- const v3d = c;
84
- this.z = v3d.z ? v3d.z : originPoint.z;
80
+ this.z = getZ(c);
85
81
  }
86
82
  sub(v) {
87
- return Vector3d.create(this.x - v.x, this.y - v.y, this.z - v.z);
83
+ return Vector3d.create(this.x - v.x, this.y - v.y, this.z - getZ(v));
88
84
  }
89
85
  subFrom(v) {
90
86
  this.x -= v.x;
91
87
  this.y -= v.y;
92
- this.z -= v.z;
88
+ this.z -= getZ(v);
93
89
  }
94
- _updateFromAngle = (angle, length) => {
90
+ _updateFromAngle(angle, length) {
95
91
  this.x = Math.cos(angle) * length;
96
92
  this.y = Math.sin(angle) * length;
97
- };
93
+ }
98
94
  }
99
95
  export class Vector extends Vector3d {
100
96
  constructor(x = originPoint.x, y = originPoint.y) {
@@ -1,7 +1,6 @@
1
1
  import { MoveDirection } from "../../../../Enums/Directions/MoveDirection.js";
2
2
  import { isNull, isNumber, isObject } from "../../../../Utils/TypeUtils.js";
3
3
  import { MoveAngle } from "./MoveAngle.js";
4
- import { MoveAttract } from "./MoveAttract.js";
5
4
  import { MoveCenter } from "./MoveCenter.js";
6
5
  import { MoveGravity } from "./MoveGravity.js";
7
6
  import { MovePath } from "./Path/MovePath.js";
@@ -10,7 +9,6 @@ import { Spin } from "./Spin.js";
10
9
  import { setRangeValue } from "../../../../Utils/MathUtils.js";
11
10
  export class Move {
12
11
  angle;
13
- attract;
14
12
  center;
15
13
  decay;
16
14
  direction;
@@ -29,7 +27,6 @@ export class Move {
29
27
  warp;
30
28
  constructor() {
31
29
  this.angle = new MoveAngle();
32
- this.attract = new MoveAttract();
33
30
  this.center = new MoveCenter();
34
31
  this.decay = 0;
35
32
  this.distance = {};
@@ -52,7 +49,6 @@ export class Move {
52
49
  return;
53
50
  }
54
51
  this.angle.load(isNumber(data.angle) ? { value: data.angle } : data.angle);
55
- this.attract.load(data.attract);
56
52
  this.center.load(data.center);
57
53
  if (data.decay !== undefined) {
58
54
  this.decay = setRangeValue(data.decay);
@@ -7,15 +7,16 @@ export function paintImage(context, dimension, image, opacity) {
7
7
  if (!image) {
8
8
  return;
9
9
  }
10
+ const prevAlpha = context.globalAlpha;
10
11
  context.globalAlpha = opacity;
11
12
  context.drawImage(image, originPoint.x, originPoint.y, dimension.width, dimension.height);
12
- context.globalAlpha = 1;
13
+ context.globalAlpha = prevAlpha;
13
14
  }
14
15
  export function clear(context, dimension) {
15
16
  context.clearRect(originPoint.x, originPoint.y, dimension.width, dimension.height);
16
17
  }
17
18
  export function drawParticle(data) {
18
- const { container, context, particle, delta, colorStyles, radius, opacity, transform } = data, pos = particle.getPosition(), transformData = particle.getTransformData(transform), drawScale = defaultZoom, drawPosition = {
19
+ const { container, context, particle, delta, colorStyles, radius, opacity, transform } = data, { effectDrawers, shapeDrawers } = container.particles, pos = particle.getPosition(), transformData = particle.getTransformData(transform), drawScale = defaultZoom, drawPosition = {
19
20
  x: pos.x,
20
21
  y: pos.y,
21
22
  };
@@ -46,42 +47,40 @@ export function drawParticle(data) {
46
47
  for (const plugin of container.plugins) {
47
48
  plugin.drawParticleTransform?.(drawData);
48
49
  }
49
- drawBeforeEffect(container, drawData);
50
- drawShapeBeforeDraw(container, drawData);
51
- drawShape(container, drawData);
52
- drawShapeAfterDraw(container, drawData);
53
- drawAfterEffect(container, drawData);
50
+ const effect = particle.effect ? effectDrawers.get(particle.effect) : undefined, shape = particle.shape ? shapeDrawers.get(particle.shape) : undefined;
51
+ drawBeforeEffect(effect, drawData);
52
+ drawShapeBeforeDraw(shape, drawData);
53
+ drawShape(shape, drawData);
54
+ drawShapeAfterDraw(shape, drawData);
55
+ drawAfterEffect(effect, drawData);
54
56
  context.resetTransform();
55
57
  }
56
- export function drawAfterEffect(container, data) {
58
+ export function drawAfterEffect(drawer, data) {
59
+ if (!drawer?.drawAfter) {
60
+ return;
61
+ }
57
62
  const { particle } = data;
58
63
  if (!particle.effect) {
59
64
  return;
60
65
  }
61
- const drawer = container.particles.effectDrawers.get(particle.effect), drawFunc = drawer?.drawAfter;
62
- if (!drawFunc) {
66
+ drawer.drawAfter(data);
67
+ }
68
+ export function drawBeforeEffect(drawer, data) {
69
+ if (!drawer?.drawBefore) {
63
70
  return;
64
71
  }
65
- drawFunc(data);
66
- }
67
- export function drawBeforeEffect(container, data) {
68
72
  const { particle } = data;
69
73
  if (!particle.effect) {
70
74
  return;
71
75
  }
72
- const drawer = container.particles.effectDrawers.get(particle.effect);
73
- if (!drawer?.drawBefore) {
74
- return;
75
- }
76
76
  drawer.drawBefore(data);
77
77
  }
78
- export function drawShape(container, data) {
79
- const { context, particle, stroke } = data;
80
- if (!particle.shape) {
78
+ export function drawShape(drawer, data) {
79
+ if (!drawer) {
81
80
  return;
82
81
  }
83
- const drawer = container.particles.shapeDrawers.get(particle.shape);
84
- if (!drawer) {
82
+ const { context, particle, stroke } = data;
83
+ if (!particle.shape) {
85
84
  return;
86
85
  }
87
86
  context.beginPath();
@@ -96,26 +95,24 @@ export function drawShape(container, data) {
96
95
  context.fill();
97
96
  }
98
97
  }
99
- export function drawShapeAfterDraw(container, data) {
100
- const { particle } = data;
101
- if (!particle.shape) {
102
- return;
103
- }
104
- const drawer = container.particles.shapeDrawers.get(particle.shape);
98
+ export function drawShapeAfterDraw(drawer, data) {
105
99
  if (!drawer?.afterDraw) {
106
100
  return;
107
101
  }
108
- drawer.afterDraw(data);
109
- }
110
- export function drawShapeBeforeDraw(container, data) {
111
102
  const { particle } = data;
112
103
  if (!particle.shape) {
113
104
  return;
114
105
  }
115
- const drawer = container.particles.shapeDrawers.get(particle.shape);
106
+ drawer.afterDraw(data);
107
+ }
108
+ export function drawShapeBeforeDraw(drawer, data) {
116
109
  if (!drawer?.beforeDraw) {
117
110
  return;
118
111
  }
112
+ const { particle } = data;
113
+ if (!particle.shape) {
114
+ return;
115
+ }
119
116
  drawer.beforeDraw(data);
120
117
  }
121
118
  export function drawParticlePlugin(context, plugin, particle, delta) {
@@ -69,8 +69,15 @@ export function getDistances(pointA, pointB) {
69
69
  const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y;
70
70
  return { dx: dx, dy: dy, distance: Math.hypot(dx, dy) };
71
71
  }
72
+ export function getDistanceSq(pointA, pointB) {
73
+ const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y;
74
+ return dx * dx + dy * dy;
75
+ }
72
76
  export function getDistance(pointA, pointB) {
73
- return getDistances(pointA, pointB).distance;
77
+ return Math.sqrt(getDistanceSq(pointA, pointB));
78
+ }
79
+ export function checkDistance(pointA, pointB, distance) {
80
+ return getDistanceSq(pointA, pointB) <= distance * distance;
74
81
  }
75
82
  export function degToRad(degrees) {
76
83
  return degrees * degToRadFactor;