@tsparticles/engine 3.0.3 → 3.2.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.
- package/373.min.js +2 -0
- package/373.min.js.LICENSE.txt +1 -0
- package/438.min.js +2 -0
- package/438.min.js.LICENSE.txt +1 -0
- package/README.md +337 -216
- package/browser/Core/Canvas.js +102 -49
- package/browser/Core/Container.js +53 -41
- package/browser/Core/Engine.js +47 -32
- package/browser/Core/Particle.js +46 -48
- package/browser/Core/Particles.js +70 -57
- package/browser/Core/Retina.js +5 -4
- package/browser/Core/Utils/Circle.js +4 -3
- package/browser/Core/Utils/Constants.js +3 -0
- package/browser/Core/Utils/EventListeners.js +19 -16
- package/browser/Core/Utils/ExternalInteractorBase.js +1 -1
- package/browser/Core/Utils/InteractionManager.js +17 -8
- package/browser/Core/Utils/ParticlesInteractorBase.js +1 -1
- package/browser/Core/Utils/QuadTree.js +5 -3
- package/browser/Core/Utils/Vector.js +7 -2
- package/browser/Core/Utils/Vector3d.js +14 -9
- package/browser/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
- package/browser/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
- package/browser/Options/Classes/ManualParticle.js +3 -2
- package/browser/Options/Classes/Options.js +3 -0
- package/browser/Utils/CanvasUtils.js +50 -40
- package/browser/Utils/ColorUtils.js +124 -45
- package/browser/Utils/EventDispatcher.js +6 -5
- package/browser/Utils/HslColorManager.js +5 -5
- package/browser/Utils/NumberUtils.js +35 -23
- package/browser/Utils/RgbColorManager.js +5 -5
- package/browser/Utils/Utils.js +102 -19
- package/cjs/Core/Canvas.js +102 -49
- package/cjs/Core/Container.js +53 -41
- package/cjs/Core/Engine.js +70 -32
- package/cjs/Core/Particle.js +45 -47
- package/cjs/Core/Particles.js +93 -57
- package/cjs/Core/Retina.js +5 -4
- package/cjs/Core/Utils/Circle.js +4 -3
- package/cjs/Core/Utils/Constants.js +4 -1
- package/cjs/Core/Utils/EventListeners.js +18 -15
- package/cjs/Core/Utils/ExternalInteractorBase.js +1 -1
- package/cjs/Core/Utils/InteractionManager.js +17 -8
- package/cjs/Core/Utils/ParticlesInteractorBase.js +1 -1
- package/cjs/Core/Utils/QuadTree.js +5 -3
- package/cjs/Core/Utils/Vector.js +7 -2
- package/cjs/Core/Utils/Vector3d.js +14 -9
- package/cjs/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
- package/cjs/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
- package/cjs/Options/Classes/ManualParticle.js +3 -2
- package/cjs/Options/Classes/Options.js +3 -0
- package/cjs/Utils/CanvasUtils.js +50 -40
- package/cjs/Utils/ColorUtils.js +126 -45
- package/cjs/Utils/EventDispatcher.js +6 -5
- package/cjs/Utils/HslColorManager.js +5 -5
- package/cjs/Utils/NumberUtils.js +37 -24
- package/cjs/Utils/RgbColorManager.js +5 -5
- package/cjs/Utils/Utils.js +103 -19
- package/dist_browser_Core_Container_js.js +92 -0
- package/dist_browser_Core_Particle_js.js +32 -0
- package/esm/Core/Canvas.js +102 -49
- package/esm/Core/Container.js +53 -41
- package/esm/Core/Engine.js +47 -32
- package/esm/Core/Particle.js +46 -48
- package/esm/Core/Particles.js +70 -57
- package/esm/Core/Retina.js +5 -4
- package/esm/Core/Utils/Circle.js +4 -3
- package/esm/Core/Utils/Constants.js +3 -0
- package/esm/Core/Utils/EventListeners.js +19 -16
- package/esm/Core/Utils/ExternalInteractorBase.js +1 -1
- package/esm/Core/Utils/InteractionManager.js +17 -8
- package/esm/Core/Utils/ParticlesInteractorBase.js +1 -1
- package/esm/Core/Utils/QuadTree.js +5 -3
- package/esm/Core/Utils/Vector.js +7 -2
- package/esm/Core/Utils/Vector3d.js +14 -9
- package/esm/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
- package/esm/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
- package/esm/Options/Classes/ManualParticle.js +3 -2
- package/esm/Options/Classes/Options.js +3 -0
- package/esm/Utils/CanvasUtils.js +50 -40
- package/esm/Utils/ColorUtils.js +124 -45
- package/esm/Utils/EventDispatcher.js +6 -5
- package/esm/Utils/HslColorManager.js +5 -5
- package/esm/Utils/NumberUtils.js +35 -23
- package/esm/Utils/RgbColorManager.js +5 -5
- package/esm/Utils/Utils.js +102 -19
- package/package.json +1 -1
- package/report.html +3 -3
- package/tsparticles.engine.js +894 -5461
- package/tsparticles.engine.min.js +1 -1
- package/tsparticles.engine.min.js.LICENSE.txt +1 -1
- package/types/Core/Canvas.d.ts +5 -3
- package/types/Core/Container.d.ts +1 -1
- package/types/Core/Engine.d.ts +13 -8
- package/types/Core/Interfaces/IContainerPlugin.d.ts +3 -3
- package/types/Core/Interfaces/IEffectDrawer.d.ts +3 -3
- package/types/Core/Interfaces/IMovePathGenerator.d.ts +2 -2
- package/types/Core/Interfaces/IParticleHslAnimation.d.ts +4 -4
- package/types/Core/Interfaces/IParticleMover.d.ts +2 -2
- package/types/Core/Interfaces/IParticleUpdater.d.ts +2 -2
- package/types/Core/Interfaces/IParticleValueAnimation.d.ts +4 -0
- package/types/Core/Interfaces/IPlugin.d.ts +1 -1
- package/types/Core/Interfaces/IShapeDrawData.d.ts +2 -2
- package/types/Core/Interfaces/IShapeDrawer.d.ts +4 -4
- package/types/Core/Particle.d.ts +3 -3
- package/types/Core/Particles.d.ts +12 -8
- package/types/Core/Utils/Constants.d.ts +3 -0
- package/types/Core/Utils/ExternalInteractorBase.d.ts +1 -1
- package/types/Core/Utils/InteractionManager.d.ts +3 -3
- package/types/Core/Utils/ParticlesInteractorBase.d.ts +1 -1
- package/types/Core/Utils/Point.d.ts +1 -1
- package/types/Enums/Modes/OutMode.d.ts +0 -3
- package/types/Options/Classes/BackgroundMask/BackgroundMaskCover.d.ts +2 -1
- package/types/Options/Classes/Options.d.ts +1 -0
- package/types/Options/Classes/Particles/Move/Move.d.ts +1 -2
- package/types/Options/Classes/Particles/Move/OutModes.d.ts +5 -6
- package/types/Options/Interfaces/BackgroundMask/IBackgroundMask.d.ts +2 -1
- package/types/Options/Interfaces/BackgroundMask/IBackgroundMaskCover.d.ts +2 -1
- package/types/Options/Interfaces/IOptions.d.ts +1 -0
- package/types/Options/Interfaces/Interactivity/Modes/IModes.d.ts +1 -3
- package/types/Options/Interfaces/Particles/Move/IMove.d.ts +2 -2
- package/types/Options/Interfaces/Particles/Move/IOutModes.d.ts +6 -6
- package/types/Types/CustomEventArgs.d.ts +2 -2
- package/types/Types/ExportResult.d.ts +2 -2
- package/types/Types/ParticlesGroups.d.ts +1 -3
- package/types/Types/PathOptions.d.ts +1 -3
- package/types/Types/ShapeData.d.ts +1 -3
- package/types/Utils/CanvasUtils.d.ts +9 -8
- package/types/Utils/ColorUtils.d.ts +5 -0
- package/types/Utils/NumberUtils.d.ts +2 -2
- package/types/Utils/Utils.d.ts +9 -6
- package/umd/Core/Canvas.js +102 -49
- package/umd/Core/Container.js +54 -42
- package/umd/Core/Engine.js +72 -33
- package/umd/Core/Particle.js +46 -48
- package/umd/Core/Particles.js +95 -58
- package/umd/Core/Retina.js +5 -4
- package/umd/Core/Utils/Circle.js +4 -3
- package/umd/Core/Utils/Constants.js +4 -1
- package/umd/Core/Utils/EventListeners.js +18 -15
- package/umd/Core/Utils/ExternalInteractorBase.js +1 -1
- package/umd/Core/Utils/InteractionManager.js +17 -8
- package/umd/Core/Utils/ParticlesInteractorBase.js +1 -1
- package/umd/Core/Utils/QuadTree.js +5 -3
- package/umd/Core/Utils/Vector.js +7 -2
- package/umd/Core/Utils/Vector3d.js +14 -9
- package/umd/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
- package/umd/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
- package/umd/Options/Classes/ManualParticle.js +3 -2
- package/umd/Options/Classes/Options.js +3 -0
- package/umd/Utils/CanvasUtils.js +50 -40
- package/umd/Utils/ColorUtils.js +127 -46
- package/umd/Utils/EventDispatcher.js +6 -5
- package/umd/Utils/HslColorManager.js +5 -5
- package/umd/Utils/NumberUtils.js +38 -25
- package/umd/Utils/RgbColorManager.js +5 -5
- package/umd/Utils/Utils.js +104 -20
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { getLogger, getPosition } from "../Utils/Utils.js";
|
|
2
2
|
import { InteractionManager } from "./Utils/InteractionManager.js";
|
|
3
|
-
import { Particle } from "./Particle.js";
|
|
4
3
|
import { Point } from "./Utils/Point.js";
|
|
5
4
|
import { QuadTree } from "./Utils/QuadTree.js";
|
|
6
5
|
import { Rectangle } from "./Utils/Rectangle.js";
|
|
7
6
|
import { errorPrefix } from "./Utils/Constants.js";
|
|
8
|
-
const qTreeCapacity = 4;
|
|
7
|
+
const qTreeCapacity = 4, squareExp = 2, defaultRemoveQuantity = 1;
|
|
9
8
|
const qTreeRectangle = (canvasSize) => {
|
|
10
9
|
const { height, width } = canvasSize, posOffset = -0.25, sizeFactor = 1.5;
|
|
11
10
|
return new Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
|
|
@@ -17,7 +16,7 @@ export class Particles {
|
|
|
17
16
|
this._pool.push(particle);
|
|
18
17
|
}
|
|
19
18
|
};
|
|
20
|
-
this._applyDensity = (options, manualCount, group) => {
|
|
19
|
+
this._applyDensity = async (options, manualCount, group) => {
|
|
21
20
|
const numberOptions = options.number;
|
|
22
21
|
if (!options.number.density?.enable) {
|
|
23
22
|
if (group === undefined) {
|
|
@@ -28,7 +27,7 @@ export class Particles {
|
|
|
28
27
|
}
|
|
29
28
|
return;
|
|
30
29
|
}
|
|
31
|
-
const densityFactor = this._initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value >
|
|
30
|
+
const densityFactor = this._initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, minLimit = 0, optParticlesLimit = numberOptions.limit.value > minLimit ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount, particlesCount = Math.min(this.count, this.filter((t) => t.group === group).length);
|
|
32
31
|
if (group === undefined) {
|
|
33
32
|
this._limit = numberOptions.limit.value * densityFactor;
|
|
34
33
|
}
|
|
@@ -36,29 +35,28 @@ export class Particles {
|
|
|
36
35
|
this._groupLimits.set(group, numberOptions.limit.value * densityFactor);
|
|
37
36
|
}
|
|
38
37
|
if (particlesCount < particlesNumber) {
|
|
39
|
-
this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
|
|
38
|
+
await this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
|
|
40
39
|
}
|
|
41
40
|
else if (particlesCount > particlesNumber) {
|
|
42
41
|
this.removeQuantity(particlesCount - particlesNumber, group);
|
|
43
42
|
}
|
|
44
43
|
};
|
|
45
44
|
this._initDensityFactor = (densityOptions) => {
|
|
46
|
-
const container = this._container;
|
|
45
|
+
const container = this._container, defaultFactor = 1;
|
|
47
46
|
if (!container.canvas.element || !densityOptions.enable) {
|
|
48
|
-
return
|
|
47
|
+
return defaultFactor;
|
|
49
48
|
}
|
|
50
49
|
const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio;
|
|
51
|
-
return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio **
|
|
50
|
+
return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp);
|
|
52
51
|
};
|
|
53
|
-
this._pushParticle = (position, overrideOptions, group, initializer) => {
|
|
52
|
+
this._pushParticle = async (position, overrideOptions, group, initializer) => {
|
|
54
53
|
try {
|
|
55
54
|
let particle = this._pool.pop();
|
|
56
|
-
if (particle) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
else {
|
|
60
|
-
particle = new Particle(this._engine, this._nextId, this._container, position, overrideOptions, group);
|
|
55
|
+
if (!particle) {
|
|
56
|
+
const { Particle } = await import("./Particle.js");
|
|
57
|
+
particle = new Particle(this._engine, this._container);
|
|
61
58
|
}
|
|
59
|
+
await particle.init(this._nextId, position, overrideOptions, group);
|
|
62
60
|
let canAdd = true;
|
|
63
61
|
if (initializer) {
|
|
64
62
|
canAdd = initializer(particle);
|
|
@@ -79,7 +77,6 @@ export class Particles {
|
|
|
79
77
|
}
|
|
80
78
|
catch (e) {
|
|
81
79
|
getLogger().warning(`${errorPrefix} adding particle: ${e}`);
|
|
82
|
-
return;
|
|
83
80
|
}
|
|
84
81
|
};
|
|
85
82
|
this._removeParticle = (index, group, override) => {
|
|
@@ -87,9 +84,9 @@ export class Particles {
|
|
|
87
84
|
if (!particle || particle.group !== group) {
|
|
88
85
|
return false;
|
|
89
86
|
}
|
|
90
|
-
const zIdx = this._zArray.indexOf(particle);
|
|
91
|
-
this._array.splice(index,
|
|
92
|
-
this._zArray.splice(zIdx,
|
|
87
|
+
const zIdx = this._zArray.indexOf(particle), deleteCount = 1;
|
|
88
|
+
this._array.splice(index, deleteCount);
|
|
89
|
+
this._zArray.splice(zIdx, deleteCount);
|
|
93
90
|
particle.destroy(override);
|
|
94
91
|
this._engine.dispatchEvent("particleRemoved", {
|
|
95
92
|
container: this._container,
|
|
@@ -111,26 +108,27 @@ export class Particles {
|
|
|
111
108
|
this._needsSort = false;
|
|
112
109
|
this._lastZIndex = 0;
|
|
113
110
|
this._interactionManager = new InteractionManager(engine, container);
|
|
111
|
+
this._pluginsInitialized = false;
|
|
114
112
|
const canvasSize = container.canvas.size;
|
|
115
113
|
this.quadTree = new QuadTree(qTreeRectangle(canvasSize), qTreeCapacity);
|
|
116
|
-
this.movers =
|
|
117
|
-
this.updaters =
|
|
114
|
+
this.movers = [];
|
|
115
|
+
this.updaters = [];
|
|
118
116
|
}
|
|
119
117
|
get count() {
|
|
120
118
|
return this._array.length;
|
|
121
119
|
}
|
|
122
|
-
addManualParticles() {
|
|
120
|
+
async addManualParticles() {
|
|
123
121
|
const container = this._container, options = container.actualOptions;
|
|
124
122
|
for (const particle of options.manualParticles) {
|
|
125
|
-
this.addParticle(particle.position ? getPosition(particle.position, container.canvas.size) : undefined, particle.options);
|
|
123
|
+
await this.addParticle(particle.position ? getPosition(particle.position, container.canvas.size) : undefined, particle.options);
|
|
126
124
|
}
|
|
127
125
|
}
|
|
128
|
-
addParticle(position, overrideOptions, group, initializer) {
|
|
129
|
-
const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count;
|
|
130
|
-
if (limit >
|
|
126
|
+
async addParticle(position, overrideOptions, group, initializer) {
|
|
127
|
+
const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count, minLimit = 0;
|
|
128
|
+
if (limit > minLimit) {
|
|
131
129
|
if (limitOptions.mode === "delete") {
|
|
132
|
-
const countToRemove = currentCount +
|
|
133
|
-
if (countToRemove >
|
|
130
|
+
const countOffset = 1, minCount = 0, countToRemove = currentCount + countOffset - limit;
|
|
131
|
+
if (countToRemove > minCount) {
|
|
134
132
|
this.removeQuantity(countToRemove);
|
|
135
133
|
}
|
|
136
134
|
}
|
|
@@ -140,11 +138,12 @@ export class Particles {
|
|
|
140
138
|
}
|
|
141
139
|
}
|
|
142
140
|
}
|
|
143
|
-
return this._pushParticle(position, overrideOptions, group, initializer);
|
|
141
|
+
return await this._pushParticle(position, overrideOptions, group, initializer);
|
|
144
142
|
}
|
|
145
143
|
clear() {
|
|
146
144
|
this._array = [];
|
|
147
145
|
this._zArray = [];
|
|
146
|
+
this._pluginsInitialized = false;
|
|
148
147
|
}
|
|
149
148
|
destroy() {
|
|
150
149
|
this._array = [];
|
|
@@ -157,10 +156,10 @@ export class Particles {
|
|
|
157
156
|
canvas.clear();
|
|
158
157
|
await this.update(delta);
|
|
159
158
|
for (const [, plugin] of container.plugins) {
|
|
160
|
-
canvas.drawPlugin(plugin, delta);
|
|
159
|
+
await canvas.drawPlugin(plugin, delta);
|
|
161
160
|
}
|
|
162
161
|
for (const p of this._zArray) {
|
|
163
|
-
p.draw(delta);
|
|
162
|
+
await p.draw(delta);
|
|
164
163
|
}
|
|
165
164
|
}
|
|
166
165
|
filter(condition) {
|
|
@@ -175,13 +174,12 @@ export class Particles {
|
|
|
175
174
|
handleClickMode(mode) {
|
|
176
175
|
this._interactionManager.handleClickMode(mode);
|
|
177
176
|
}
|
|
178
|
-
init() {
|
|
177
|
+
async init() {
|
|
179
178
|
const container = this._container, options = container.actualOptions;
|
|
180
179
|
this._lastZIndex = 0;
|
|
181
180
|
this._needsSort = false;
|
|
181
|
+
await this.initPlugins();
|
|
182
182
|
let handled = false;
|
|
183
|
-
this.updaters = this._engine.getUpdaters(container, true);
|
|
184
|
-
this._interactionManager.init();
|
|
185
183
|
for (const [, plugin] of container.plugins) {
|
|
186
184
|
if (plugin.particlesInitialization !== undefined) {
|
|
187
185
|
handled = plugin.particlesInitialization();
|
|
@@ -190,55 +188,67 @@ export class Particles {
|
|
|
190
188
|
break;
|
|
191
189
|
}
|
|
192
190
|
}
|
|
193
|
-
this.
|
|
194
|
-
for (const [, pathGenerator] of container.pathGenerators) {
|
|
195
|
-
pathGenerator.init(container);
|
|
196
|
-
}
|
|
197
|
-
this.addManualParticles();
|
|
191
|
+
await this.addManualParticles();
|
|
198
192
|
if (!handled) {
|
|
199
193
|
const particlesOptions = options.particles, groups = particlesOptions.groups;
|
|
200
194
|
for (const group in groups) {
|
|
201
195
|
const groupOptions = groups[group];
|
|
202
196
|
for (let i = this.count, j = 0; j < groupOptions.number?.value && i < particlesOptions.number.value; i++, j++) {
|
|
203
|
-
this.addParticle(undefined, groupOptions, group);
|
|
197
|
+
await this.addParticle(undefined, groupOptions, group);
|
|
204
198
|
}
|
|
205
199
|
}
|
|
206
200
|
for (let i = this.count; i < particlesOptions.number.value; i++) {
|
|
207
|
-
this.addParticle();
|
|
201
|
+
await this.addParticle();
|
|
208
202
|
}
|
|
209
203
|
}
|
|
210
204
|
}
|
|
211
|
-
|
|
205
|
+
async initPlugins() {
|
|
206
|
+
if (this._pluginsInitialized) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const container = this._container;
|
|
210
|
+
this.movers = await this._engine.getMovers(container, true);
|
|
211
|
+
this.updaters = await this._engine.getUpdaters(container, true);
|
|
212
|
+
await this._interactionManager.init();
|
|
213
|
+
for (const [, pathGenerator] of container.pathGenerators) {
|
|
214
|
+
await pathGenerator.init(container);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async push(nb, mouse, overrideOptions, group) {
|
|
212
218
|
for (let i = 0; i < nb; i++) {
|
|
213
|
-
this.addParticle(mouse?.position, overrideOptions, group);
|
|
219
|
+
await this.addParticle(mouse?.position, overrideOptions, group);
|
|
214
220
|
}
|
|
215
221
|
}
|
|
216
222
|
async redraw() {
|
|
217
223
|
this.clear();
|
|
218
|
-
this.init();
|
|
224
|
+
await this.init();
|
|
219
225
|
await this.draw({ value: 0, factor: 0 });
|
|
220
226
|
}
|
|
221
227
|
remove(particle, group, override) {
|
|
222
228
|
this.removeAt(this._array.indexOf(particle), undefined, group, override);
|
|
223
229
|
}
|
|
224
|
-
removeAt(index, quantity =
|
|
225
|
-
|
|
230
|
+
removeAt(index, quantity = defaultRemoveQuantity, group, override) {
|
|
231
|
+
const minIndex = 0;
|
|
232
|
+
if (index < minIndex || index > this.count) {
|
|
226
233
|
return;
|
|
227
234
|
}
|
|
228
235
|
let deleted = 0;
|
|
229
236
|
for (let i = index; deleted < quantity && i < this.count; i++) {
|
|
230
|
-
this._removeParticle(i--, group, override)
|
|
237
|
+
if (this._removeParticle(i--, group, override)) {
|
|
238
|
+
deleted++;
|
|
239
|
+
}
|
|
231
240
|
}
|
|
232
241
|
}
|
|
233
242
|
removeQuantity(quantity, group) {
|
|
234
|
-
|
|
243
|
+
const defaultIndex = 0;
|
|
244
|
+
this.removeAt(defaultIndex, quantity, group);
|
|
235
245
|
}
|
|
236
|
-
setDensity() {
|
|
237
|
-
const options = this._container.actualOptions, groups = options.particles.groups;
|
|
246
|
+
async setDensity() {
|
|
247
|
+
const options = this._container.actualOptions, groups = options.particles.groups, manualCount = 0;
|
|
238
248
|
for (const group in groups) {
|
|
239
|
-
this._applyDensity(groups[group],
|
|
249
|
+
await this._applyDensity(groups[group], manualCount, group);
|
|
240
250
|
}
|
|
241
|
-
this._applyDensity(options.particles, options.manualParticles.length);
|
|
251
|
+
await this._applyDensity(options.particles, options.manualParticles.length);
|
|
242
252
|
}
|
|
243
253
|
setLastZIndex(zIndex) {
|
|
244
254
|
this._lastZIndex = zIndex;
|
|
@@ -254,7 +264,7 @@ export class Particles {
|
|
|
254
264
|
pathGenerator.update();
|
|
255
265
|
}
|
|
256
266
|
for (const [, plugin] of container.plugins) {
|
|
257
|
-
|
|
267
|
+
await plugin.update?.(delta);
|
|
258
268
|
}
|
|
259
269
|
const resizeFactor = this._resizeFactor;
|
|
260
270
|
for (const particle of this._array) {
|
|
@@ -265,15 +275,17 @@ export class Particles {
|
|
|
265
275
|
particle.initialPosition.y *= resizeFactor.height;
|
|
266
276
|
}
|
|
267
277
|
particle.ignoresResizeRatio = false;
|
|
268
|
-
|
|
278
|
+
this._interactionManager.reset(particle);
|
|
269
279
|
for (const [, plugin] of this._container.plugins) {
|
|
270
280
|
if (particle.destroyed) {
|
|
271
281
|
break;
|
|
272
282
|
}
|
|
273
|
-
plugin.particleUpdate
|
|
283
|
+
plugin.particleUpdate?.(particle, delta);
|
|
274
284
|
}
|
|
275
285
|
for (const mover of this.movers) {
|
|
276
|
-
mover.isEnabled(particle)
|
|
286
|
+
if (mover.isEnabled(particle)) {
|
|
287
|
+
await mover.move(particle, delta);
|
|
288
|
+
}
|
|
277
289
|
}
|
|
278
290
|
if (particle.destroyed) {
|
|
279
291
|
particlesToDelete.add(particle);
|
|
@@ -298,7 +310,7 @@ export class Particles {
|
|
|
298
310
|
await this._interactionManager.externalInteract(delta);
|
|
299
311
|
for (const particle of this._array) {
|
|
300
312
|
for (const updater of this.updaters) {
|
|
301
|
-
updater.update(particle, delta);
|
|
313
|
+
await updater.update(particle, delta);
|
|
302
314
|
}
|
|
303
315
|
if (!particle.destroyed && !particle.spawning) {
|
|
304
316
|
await this._interactionManager.particlesInteract(particle, delta);
|
|
@@ -308,7 +320,8 @@ export class Particles {
|
|
|
308
320
|
if (this._needsSort) {
|
|
309
321
|
const zArray = this._zArray;
|
|
310
322
|
zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
|
|
311
|
-
|
|
323
|
+
const lengthOffset = 1;
|
|
324
|
+
this._lastZIndex = zArray[zArray.length - lengthOffset].position.z;
|
|
312
325
|
this._needsSort = false;
|
|
313
326
|
}
|
|
314
327
|
}
|
package/browser/Core/Retina.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { getRangeValue } from "../Utils/NumberUtils.js";
|
|
2
2
|
import { isSsr } from "../Utils/Utils.js";
|
|
3
|
+
const defaultRatio = 1, defaultReduceFactor = 1;
|
|
3
4
|
export class Retina {
|
|
4
5
|
constructor(container) {
|
|
5
6
|
this.container = container;
|
|
6
|
-
this.pixelRatio =
|
|
7
|
-
this.reduceFactor =
|
|
7
|
+
this.pixelRatio = defaultRatio;
|
|
8
|
+
this.reduceFactor = defaultReduceFactor;
|
|
8
9
|
}
|
|
9
10
|
init() {
|
|
10
11
|
const container = this.container, options = container.actualOptions;
|
|
11
|
-
this.pixelRatio = !options.detectRetina || isSsr() ?
|
|
12
|
-
this.reduceFactor =
|
|
12
|
+
this.pixelRatio = !options.detectRetina || isSsr() ? defaultRatio : window.devicePixelRatio;
|
|
13
|
+
this.reduceFactor = defaultReduceFactor;
|
|
13
14
|
const ratio = this.pixelRatio, canvas = container.canvas;
|
|
14
15
|
if (canvas.element) {
|
|
15
16
|
const element = canvas.element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Range } from "./Range.js";
|
|
2
2
|
import { Rectangle } from "./Rectangle.js";
|
|
3
3
|
import { getDistance } from "../../Utils/NumberUtils.js";
|
|
4
|
+
const squareExp = 2;
|
|
4
5
|
export class Circle extends Range {
|
|
5
6
|
constructor(x, y, radius) {
|
|
6
7
|
super(x, y);
|
|
@@ -12,12 +13,12 @@ export class Circle extends Range {
|
|
|
12
13
|
intersects(range) {
|
|
13
14
|
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;
|
|
14
15
|
if (range instanceof Circle) {
|
|
15
|
-
const rSum = r + range.radius, dist = Math.sqrt(distPos.x **
|
|
16
|
+
const rSum = r + range.radius, dist = Math.sqrt(distPos.x ** squareExp + distPos.y ** squareExp);
|
|
16
17
|
return rSum > dist;
|
|
17
18
|
}
|
|
18
19
|
else if (range instanceof Rectangle) {
|
|
19
|
-
const { width, height } = range.size, edges = Math.pow(distPos.x - width,
|
|
20
|
-
return (edges <= r **
|
|
20
|
+
const { width, height } = range.size, edges = Math.pow(distPos.x - width, squareExp) + Math.pow(distPos.y - height, squareExp);
|
|
21
|
+
return (edges <= r ** squareExp ||
|
|
21
22
|
(distPos.x <= r + width && distPos.y <= r + height) ||
|
|
22
23
|
distPos.x <= width ||
|
|
23
24
|
distPos.y <= height);
|
|
@@ -11,3 +11,6 @@ export const touchCancelEvent = "touchcancel";
|
|
|
11
11
|
export const resizeEvent = "resize";
|
|
12
12
|
export const visibilityChangeEvent = "visibilitychange";
|
|
13
13
|
export const errorPrefix = "tsParticles - Error";
|
|
14
|
+
export const percentDenominator = 100;
|
|
15
|
+
export const halfRandom = 0.5;
|
|
16
|
+
export const millisecondsToSeconds = 1000;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { executeOnSingleOrMultiple, isBoolean, safeMatchMedia } from "../../Utils/Utils.js";
|
|
2
|
-
import { mouseDownEvent, mouseLeaveEvent, mouseMoveEvent, mouseOutEvent, mouseUpEvent, resizeEvent, touchCancelEvent, touchEndEvent, touchMoveEvent, touchStartEvent, visibilityChangeEvent, } from "./Constants.js";
|
|
2
|
+
import { millisecondsToSeconds, mouseDownEvent, mouseLeaveEvent, mouseMoveEvent, mouseOutEvent, mouseUpEvent, resizeEvent, touchCancelEvent, touchEndEvent, touchMoveEvent, touchStartEvent, visibilityChangeEvent, } from "./Constants.js";
|
|
3
|
+
const double = 2;
|
|
3
4
|
function manageListener(element, event, handler, add, options) {
|
|
4
5
|
if (add) {
|
|
5
6
|
let addOptions = { passive: true };
|
|
@@ -32,13 +33,14 @@ export class EventListeners {
|
|
|
32
33
|
executeOnSingleOrMultiple(onClick.mode, (mode) => this.container.handleClickMode(mode));
|
|
33
34
|
}
|
|
34
35
|
if (e.type === "touchend") {
|
|
35
|
-
|
|
36
|
+
const touchDelay = 500;
|
|
37
|
+
setTimeout(() => this._mouseTouchFinish(), touchDelay);
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
this._handleThemeChange = (e) => {
|
|
39
41
|
const mediaEvent = e, container = this.container, options = container.options, defaultThemes = options.defaultThemes, themeName = mediaEvent.matches ? defaultThemes.dark : defaultThemes.light, theme = options.themes.find((theme) => theme.name === themeName);
|
|
40
42
|
if (theme && theme.default.auto) {
|
|
41
|
-
container.loadTheme(themeName);
|
|
43
|
+
void container.loadTheme(themeName);
|
|
42
44
|
}
|
|
43
45
|
};
|
|
44
46
|
this._handleVisibilityChange = () => {
|
|
@@ -53,7 +55,7 @@ export class EventListeners {
|
|
|
53
55
|
}
|
|
54
56
|
else {
|
|
55
57
|
container.pageHidden = false;
|
|
56
|
-
if (container.
|
|
58
|
+
if (container.animationStatus) {
|
|
57
59
|
container.play(true);
|
|
58
60
|
}
|
|
59
61
|
else {
|
|
@@ -61,15 +63,16 @@ export class EventListeners {
|
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
};
|
|
64
|
-
this._handleWindowResize =
|
|
66
|
+
this._handleWindowResize = () => {
|
|
65
67
|
if (this._resizeTimeout) {
|
|
66
68
|
clearTimeout(this._resizeTimeout);
|
|
67
69
|
delete this._resizeTimeout;
|
|
68
70
|
}
|
|
69
|
-
|
|
71
|
+
const handleResize = async () => {
|
|
70
72
|
const canvas = this.container.canvas;
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
+
await canvas?.windowResize();
|
|
74
|
+
};
|
|
75
|
+
this._resizeTimeout = setTimeout(() => void handleResize(), this.container.actualOptions.interactivity.events.resize.delay * millisecondsToSeconds);
|
|
73
76
|
};
|
|
74
77
|
this._manageInteractivityListeners = (mouseLeaveTmpEvent, add) => {
|
|
75
78
|
const handlers = this._handlers, container = this.container, options = container.actualOptions;
|
|
@@ -155,12 +158,12 @@ export class EventListeners {
|
|
|
155
158
|
delete this._resizeObserver;
|
|
156
159
|
}
|
|
157
160
|
else if (!this._resizeObserver && add && canvasEl) {
|
|
158
|
-
this._resizeObserver = new ResizeObserver(
|
|
161
|
+
this._resizeObserver = new ResizeObserver((entries) => {
|
|
159
162
|
const entry = entries.find((e) => e.target === canvasEl);
|
|
160
163
|
if (!entry) {
|
|
161
164
|
return;
|
|
162
165
|
}
|
|
163
|
-
|
|
166
|
+
this._handleWindowResize();
|
|
164
167
|
});
|
|
165
168
|
this._resizeObserver.observe(canvasEl);
|
|
166
169
|
}
|
|
@@ -211,7 +214,7 @@ export class EventListeners {
|
|
|
211
214
|
};
|
|
212
215
|
this._mouseTouchMove = (e) => {
|
|
213
216
|
const container = this.container, options = container.actualOptions, interactivity = container.interactivity, canvasEl = container.canvas.element;
|
|
214
|
-
if (!interactivity
|
|
217
|
+
if (!interactivity?.element) {
|
|
215
218
|
return;
|
|
216
219
|
}
|
|
217
220
|
interactivity.mouse.inside = true;
|
|
@@ -233,8 +236,8 @@ export class EventListeners {
|
|
|
233
236
|
if (source && target && canvasEl) {
|
|
234
237
|
const sourceRect = source.getBoundingClientRect(), targetRect = target.getBoundingClientRect(), canvasRect = canvasEl.getBoundingClientRect();
|
|
235
238
|
pos = {
|
|
236
|
-
x: mouseEvent.offsetX +
|
|
237
|
-
y: mouseEvent.offsetY +
|
|
239
|
+
x: mouseEvent.offsetX + double * sourceRect.left - (targetRect.left + canvasRect.left),
|
|
240
|
+
y: mouseEvent.offsetY + double * sourceRect.top - (targetRect.top + canvasRect.top),
|
|
238
241
|
};
|
|
239
242
|
}
|
|
240
243
|
else {
|
|
@@ -254,10 +257,10 @@ export class EventListeners {
|
|
|
254
257
|
else {
|
|
255
258
|
this._canPush = e.type !== "touchmove";
|
|
256
259
|
if (canvasEl) {
|
|
257
|
-
const touchEvent = e, lastTouch = touchEvent.touches[touchEvent.touches.length -
|
|
260
|
+
const touchEvent = e, lengthOffset = 1, lastTouch = touchEvent.touches[touchEvent.touches.length - lengthOffset], canvasRect = canvasEl.getBoundingClientRect(), defaultCoordinate = 0;
|
|
258
261
|
pos = {
|
|
259
|
-
x: lastTouch.clientX - (canvasRect.left ??
|
|
260
|
-
y: lastTouch.clientY - (canvasRect.top ??
|
|
262
|
+
x: lastTouch.clientX - (canvasRect.left ?? defaultCoordinate),
|
|
263
|
+
y: lastTouch.clientY - (canvasRect.top ?? defaultCoordinate),
|
|
261
264
|
};
|
|
262
265
|
}
|
|
263
266
|
}
|
|
@@ -2,21 +2,24 @@ export class InteractionManager {
|
|
|
2
2
|
constructor(engine, container) {
|
|
3
3
|
this.container = container;
|
|
4
4
|
this._engine = engine;
|
|
5
|
-
this._interactors =
|
|
5
|
+
this._interactors = [];
|
|
6
6
|
this._externalInteractors = [];
|
|
7
7
|
this._particleInteractors = [];
|
|
8
8
|
}
|
|
9
9
|
async externalInteract(delta) {
|
|
10
10
|
for (const interactor of this._externalInteractors) {
|
|
11
|
-
|
|
11
|
+
if (interactor.isEnabled()) {
|
|
12
|
+
await interactor.interact(delta);
|
|
13
|
+
}
|
|
12
14
|
}
|
|
13
15
|
}
|
|
14
16
|
handleClickMode(mode) {
|
|
15
17
|
for (const interactor of this._externalInteractors) {
|
|
16
|
-
interactor.handleClickMode
|
|
18
|
+
interactor.handleClickMode?.(mode);
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
|
-
init() {
|
|
21
|
+
async init() {
|
|
22
|
+
this._interactors = await this._engine.getInteractors(this.container, true);
|
|
20
23
|
this._externalInteractors = [];
|
|
21
24
|
this._particleInteractors = [];
|
|
22
25
|
for (const interactor of this._interactors) {
|
|
@@ -36,15 +39,21 @@ export class InteractionManager {
|
|
|
36
39
|
interactor.clear(particle, delta);
|
|
37
40
|
}
|
|
38
41
|
for (const interactor of this._particleInteractors) {
|
|
39
|
-
|
|
42
|
+
if (interactor.isEnabled(particle)) {
|
|
43
|
+
await interactor.interact(particle, delta);
|
|
44
|
+
}
|
|
40
45
|
}
|
|
41
46
|
}
|
|
42
|
-
|
|
47
|
+
reset(particle) {
|
|
43
48
|
for (const interactor of this._externalInteractors) {
|
|
44
|
-
interactor.isEnabled()
|
|
49
|
+
if (interactor.isEnabled()) {
|
|
50
|
+
interactor.reset(particle);
|
|
51
|
+
}
|
|
45
52
|
}
|
|
46
53
|
for (const interactor of this._particleInteractors) {
|
|
47
|
-
interactor.isEnabled(particle)
|
|
54
|
+
if (interactor.isEnabled(particle)) {
|
|
55
|
+
interactor.reset(particle);
|
|
56
|
+
}
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
59
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { Circle } from "./Circle.js";
|
|
2
2
|
import { Rectangle } from "./Rectangle.js";
|
|
3
3
|
import { getDistance } from "../../Utils/NumberUtils.js";
|
|
4
|
+
const half = 0.5, double = 2, subdivideCount = 4;
|
|
4
5
|
export class QuadTree {
|
|
5
6
|
constructor(rectangle, capacity) {
|
|
6
7
|
this.rectangle = rectangle;
|
|
7
8
|
this.capacity = capacity;
|
|
8
9
|
this._subdivide = () => {
|
|
9
10
|
const { x, y } = this.rectangle.position, { width, height } = this.rectangle.size, { capacity } = this;
|
|
10
|
-
for (let i = 0; i <
|
|
11
|
-
|
|
11
|
+
for (let i = 0; i < subdivideCount; i++) {
|
|
12
|
+
const fixedIndex = i % double;
|
|
13
|
+
this._subs.push(new QuadTree(new Rectangle(x + width * half * fixedIndex, y + height * half * (Math.round(i * half) - fixedIndex), width * half, height * half), capacity));
|
|
12
14
|
}
|
|
13
15
|
this._divided = true;
|
|
14
16
|
};
|
|
@@ -30,7 +32,7 @@ export class QuadTree {
|
|
|
30
32
|
return this._subs.some((sub) => sub.insert(point));
|
|
31
33
|
}
|
|
32
34
|
query(range, check, found) {
|
|
33
|
-
const res = found
|
|
35
|
+
const res = found ?? [];
|
|
34
36
|
if (!range.intersects(this.rectangle)) {
|
|
35
37
|
return [];
|
|
36
38
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { Vector3d } from "./Vector3d.js";
|
|
2
|
+
const origin = {
|
|
3
|
+
x: 0,
|
|
4
|
+
y: 0,
|
|
5
|
+
z: 0,
|
|
6
|
+
};
|
|
2
7
|
export class Vector extends Vector3d {
|
|
3
8
|
constructor(xOrCoords, y) {
|
|
4
|
-
super(xOrCoords, y,
|
|
9
|
+
super(xOrCoords, y, origin.z);
|
|
5
10
|
}
|
|
6
11
|
static get origin() {
|
|
7
|
-
return Vector.create(
|
|
12
|
+
return Vector.create(origin.x, origin.y);
|
|
8
13
|
}
|
|
9
14
|
static clone(source) {
|
|
10
15
|
return Vector.create(source.x, source.y);
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { errorPrefix } from "./Constants.js";
|
|
2
2
|
import { isNumber } from "../../Utils/Utils.js";
|
|
3
|
+
const origin = {
|
|
4
|
+
x: 0,
|
|
5
|
+
y: 0,
|
|
6
|
+
z: 0,
|
|
7
|
+
}, squareExp = 2, inverseFactorNumerator = 1.0;
|
|
3
8
|
export class Vector3d {
|
|
4
9
|
constructor(xOrCoords, y, z) {
|
|
5
10
|
this._updateFromAngle = (angle, length) => {
|
|
@@ -10,19 +15,19 @@ export class Vector3d {
|
|
|
10
15
|
this.x = xOrCoords.x;
|
|
11
16
|
this.y = xOrCoords.y;
|
|
12
17
|
const coords3d = xOrCoords;
|
|
13
|
-
this.z = coords3d.z ? coords3d.z :
|
|
18
|
+
this.z = coords3d.z ? coords3d.z : origin.z;
|
|
14
19
|
}
|
|
15
20
|
else if (xOrCoords !== undefined && y !== undefined) {
|
|
16
21
|
this.x = xOrCoords;
|
|
17
22
|
this.y = y;
|
|
18
|
-
this.z = z ??
|
|
23
|
+
this.z = z ?? origin.z;
|
|
19
24
|
}
|
|
20
25
|
else {
|
|
21
26
|
throw new Error(`${errorPrefix} Vector3d not initialized correctly`);
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
static get origin() {
|
|
25
|
-
return Vector3d.create(
|
|
30
|
+
return Vector3d.create(origin.x, origin.y, origin.z);
|
|
26
31
|
}
|
|
27
32
|
get angle() {
|
|
28
33
|
return Math.atan2(this.y, this.x);
|
|
@@ -68,7 +73,7 @@ export class Vector3d {
|
|
|
68
73
|
this.z /= n;
|
|
69
74
|
}
|
|
70
75
|
getLengthSq() {
|
|
71
|
-
return this.x **
|
|
76
|
+
return this.x ** squareExp + this.y ** squareExp;
|
|
72
77
|
}
|
|
73
78
|
mult(n) {
|
|
74
79
|
return Vector3d.create(this.x * n, this.y * n, this.z * n);
|
|
@@ -79,19 +84,19 @@ export class Vector3d {
|
|
|
79
84
|
this.z *= n;
|
|
80
85
|
}
|
|
81
86
|
normalize() {
|
|
82
|
-
const length = this.length;
|
|
83
|
-
if (length !=
|
|
84
|
-
this.multTo(
|
|
87
|
+
const length = this.length, noLength = 0;
|
|
88
|
+
if (length != noLength) {
|
|
89
|
+
this.multTo(inverseFactorNumerator / length);
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
rotate(angle) {
|
|
88
|
-
return Vector3d.create(this.x * Math.cos(angle) - this.y * Math.sin(angle), this.x * Math.sin(angle) + this.y * Math.cos(angle),
|
|
93
|
+
return Vector3d.create(this.x * Math.cos(angle) - this.y * Math.sin(angle), this.x * Math.sin(angle) + this.y * Math.cos(angle), origin.z);
|
|
89
94
|
}
|
|
90
95
|
setTo(c) {
|
|
91
96
|
this.x = c.x;
|
|
92
97
|
this.y = c.y;
|
|
93
98
|
const v3d = c;
|
|
94
|
-
this.z = v3d.z ? v3d.z :
|
|
99
|
+
this.z = v3d.z ? v3d.z : origin.z;
|
|
95
100
|
}
|
|
96
101
|
sub(v) {
|
|
97
102
|
return Vector3d.create(this.x - v.x, this.y - v.y, this.z - v.z);
|
|
@@ -15,7 +15,7 @@ export class BackgroundMask {
|
|
|
15
15
|
}
|
|
16
16
|
if (data.cover !== undefined) {
|
|
17
17
|
const cover = data.cover, color = (isString(data.cover) ? { color: data.cover } : data.cover);
|
|
18
|
-
this.cover.load(cover.color !== undefined ? cover : { color: color });
|
|
18
|
+
this.cover.load(cover.color !== undefined || cover.image !== undefined ? cover : { color: color });
|
|
19
19
|
}
|
|
20
20
|
if (data.enable !== undefined) {
|
|
21
21
|
this.enable = data.enable;
|