@tsparticles/engine 3.0.2 → 3.1.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/README.md +283 -163
- package/browser/Core/Canvas.js +19 -19
- package/browser/Core/Container.js +45 -34
- package/browser/Core/Engine.js +36 -20
- package/browser/Core/Particle.js +35 -36
- package/browser/Core/Particles.js +30 -24
- 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 +18 -15
- package/browser/Core/Utils/ExternalInteractorBase.js +1 -1
- package/browser/Core/Utils/InteractionManager.js +14 -6
- 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/ManualParticle.js +3 -2
- package/browser/Options/Classes/Options.js +3 -0
- package/browser/Utils/CanvasUtils.js +36 -26
- 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 +19 -19
- package/cjs/Core/Container.js +45 -34
- package/cjs/Core/Engine.js +36 -20
- package/cjs/Core/Particle.js +34 -35
- package/cjs/Core/Particles.js +30 -24
- 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 +17 -14
- package/cjs/Core/Utils/ExternalInteractorBase.js +1 -1
- package/cjs/Core/Utils/InteractionManager.js +14 -6
- 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/ManualParticle.js +3 -2
- package/cjs/Options/Classes/Options.js +3 -0
- package/cjs/Utils/CanvasUtils.js +36 -26
- 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/esm/Core/Canvas.js +19 -19
- package/esm/Core/Container.js +45 -34
- package/esm/Core/Engine.js +36 -20
- package/esm/Core/Particle.js +35 -36
- package/esm/Core/Particles.js +30 -24
- 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 +18 -15
- package/esm/Core/Utils/ExternalInteractorBase.js +1 -1
- package/esm/Core/Utils/InteractionManager.js +14 -6
- 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/ManualParticle.js +3 -2
- package/esm/Options/Classes/Options.js +3 -0
- package/esm/Utils/CanvasUtils.js +36 -26
- 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 +2 -2
- package/tsparticles.engine.js +693 -334
- package/tsparticles.engine.min.js +1 -1
- package/tsparticles.engine.min.js.LICENSE.txt +1 -1
- package/types/Core/Interfaces/IParticleHslAnimation.d.ts +4 -4
- package/types/Core/Interfaces/IParticleValueAnimation.d.ts +4 -0
- package/types/Core/Interfaces/IShapeDrawData.d.ts +2 -2
- 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 +1 -1
- package/types/Core/Utils/ParticlesInteractorBase.d.ts +1 -1
- package/types/Core/Utils/Point.d.ts +1 -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 +1 -2
- package/types/Options/Interfaces/IOptions.d.ts +1 -0
- package/types/Options/Interfaces/Interactivity/Modes/IModes.d.ts +1 -3
- 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 +3 -2
- 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 +19 -19
- package/umd/Core/Container.js +46 -35
- package/umd/Core/Engine.js +36 -20
- package/umd/Core/Particle.js +35 -36
- package/umd/Core/Particles.js +30 -24
- 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 +17 -14
- package/umd/Core/Utils/ExternalInteractorBase.js +1 -1
- package/umd/Core/Utils/InteractionManager.js +14 -6
- 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/ManualParticle.js +3 -2
- package/umd/Options/Classes/Options.js +3 -0
- package/umd/Utils/CanvasUtils.js +36 -26
- 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
|
@@ -5,7 +5,7 @@ import { Point } from "./Utils/Point.js";
|
|
|
5
5
|
import { QuadTree } from "./Utils/QuadTree.js";
|
|
6
6
|
import { Rectangle } from "./Utils/Rectangle.js";
|
|
7
7
|
import { errorPrefix } from "./Utils/Constants.js";
|
|
8
|
-
const qTreeCapacity = 4;
|
|
8
|
+
const qTreeCapacity = 4, squareExp = 2, defaultRemoveQuantity = 1;
|
|
9
9
|
const qTreeRectangle = (canvasSize) => {
|
|
10
10
|
const { height, width } = canvasSize, posOffset = -0.25, sizeFactor = 1.5;
|
|
11
11
|
return new Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
|
|
@@ -28,7 +28,7 @@ export class Particles {
|
|
|
28
28
|
}
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
|
-
const densityFactor = this._initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value >
|
|
31
|
+
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
32
|
if (group === undefined) {
|
|
33
33
|
this._limit = numberOptions.limit.value * densityFactor;
|
|
34
34
|
}
|
|
@@ -43,12 +43,12 @@ export class Particles {
|
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
45
|
this._initDensityFactor = (densityOptions) => {
|
|
46
|
-
const container = this._container;
|
|
46
|
+
const container = this._container, defaultFactor = 1;
|
|
47
47
|
if (!container.canvas.element || !densityOptions.enable) {
|
|
48
|
-
return
|
|
48
|
+
return defaultFactor;
|
|
49
49
|
}
|
|
50
50
|
const canvas = container.canvas.element, pxRatio = container.retina.pixelRatio;
|
|
51
|
-
return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio **
|
|
51
|
+
return (canvas.width * canvas.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp);
|
|
52
52
|
};
|
|
53
53
|
this._pushParticle = (position, overrideOptions, group, initializer) => {
|
|
54
54
|
try {
|
|
@@ -79,7 +79,6 @@ export class Particles {
|
|
|
79
79
|
}
|
|
80
80
|
catch (e) {
|
|
81
81
|
getLogger().warning(`${errorPrefix} adding particle: ${e}`);
|
|
82
|
-
return;
|
|
83
82
|
}
|
|
84
83
|
};
|
|
85
84
|
this._removeParticle = (index, group, override) => {
|
|
@@ -87,9 +86,9 @@ export class Particles {
|
|
|
87
86
|
if (!particle || particle.group !== group) {
|
|
88
87
|
return false;
|
|
89
88
|
}
|
|
90
|
-
const zIdx = this._zArray.indexOf(particle);
|
|
91
|
-
this._array.splice(index,
|
|
92
|
-
this._zArray.splice(zIdx,
|
|
89
|
+
const zIdx = this._zArray.indexOf(particle), deleteCount = 1;
|
|
90
|
+
this._array.splice(index, deleteCount);
|
|
91
|
+
this._zArray.splice(zIdx, deleteCount);
|
|
93
92
|
particle.destroy(override);
|
|
94
93
|
this._engine.dispatchEvent("particleRemoved", {
|
|
95
94
|
container: this._container,
|
|
@@ -126,11 +125,11 @@ export class Particles {
|
|
|
126
125
|
}
|
|
127
126
|
}
|
|
128
127
|
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 >
|
|
128
|
+
const limitOptions = this._container.actualOptions.particles.number.limit, limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit, currentCount = this.count, minLimit = 0;
|
|
129
|
+
if (limit > minLimit) {
|
|
131
130
|
if (limitOptions.mode === "delete") {
|
|
132
|
-
const countToRemove = currentCount +
|
|
133
|
-
if (countToRemove >
|
|
131
|
+
const countOffset = 1, minCount = 0, countToRemove = currentCount + countOffset - limit;
|
|
132
|
+
if (countToRemove > minCount) {
|
|
134
133
|
this.removeQuantity(countToRemove);
|
|
135
134
|
}
|
|
136
135
|
}
|
|
@@ -221,22 +220,26 @@ export class Particles {
|
|
|
221
220
|
remove(particle, group, override) {
|
|
222
221
|
this.removeAt(this._array.indexOf(particle), undefined, group, override);
|
|
223
222
|
}
|
|
224
|
-
removeAt(index, quantity =
|
|
225
|
-
|
|
223
|
+
removeAt(index, quantity = defaultRemoveQuantity, group, override) {
|
|
224
|
+
const minIndex = 0;
|
|
225
|
+
if (index < minIndex || index > this.count) {
|
|
226
226
|
return;
|
|
227
227
|
}
|
|
228
228
|
let deleted = 0;
|
|
229
229
|
for (let i = index; deleted < quantity && i < this.count; i++) {
|
|
230
|
-
this._removeParticle(i--, group, override)
|
|
230
|
+
if (this._removeParticle(i--, group, override)) {
|
|
231
|
+
deleted++;
|
|
232
|
+
}
|
|
231
233
|
}
|
|
232
234
|
}
|
|
233
235
|
removeQuantity(quantity, group) {
|
|
234
|
-
|
|
236
|
+
const defaultIndex = 0;
|
|
237
|
+
this.removeAt(defaultIndex, quantity, group);
|
|
235
238
|
}
|
|
236
239
|
setDensity() {
|
|
237
|
-
const options = this._container.actualOptions, groups = options.particles.groups;
|
|
240
|
+
const options = this._container.actualOptions, groups = options.particles.groups, manualCount = 0;
|
|
238
241
|
for (const group in groups) {
|
|
239
|
-
this._applyDensity(groups[group],
|
|
242
|
+
this._applyDensity(groups[group], manualCount, group);
|
|
240
243
|
}
|
|
241
244
|
this._applyDensity(options.particles, options.manualParticles.length);
|
|
242
245
|
}
|
|
@@ -254,7 +257,7 @@ export class Particles {
|
|
|
254
257
|
pathGenerator.update();
|
|
255
258
|
}
|
|
256
259
|
for (const [, plugin] of container.plugins) {
|
|
257
|
-
|
|
260
|
+
await plugin.update?.(delta);
|
|
258
261
|
}
|
|
259
262
|
const resizeFactor = this._resizeFactor;
|
|
260
263
|
for (const particle of this._array) {
|
|
@@ -265,15 +268,17 @@ export class Particles {
|
|
|
265
268
|
particle.initialPosition.y *= resizeFactor.height;
|
|
266
269
|
}
|
|
267
270
|
particle.ignoresResizeRatio = false;
|
|
268
|
-
|
|
271
|
+
this._interactionManager.reset(particle);
|
|
269
272
|
for (const [, plugin] of this._container.plugins) {
|
|
270
273
|
if (particle.destroyed) {
|
|
271
274
|
break;
|
|
272
275
|
}
|
|
273
|
-
plugin.particleUpdate
|
|
276
|
+
plugin.particleUpdate?.(particle, delta);
|
|
274
277
|
}
|
|
275
278
|
for (const mover of this.movers) {
|
|
276
|
-
mover.isEnabled(particle)
|
|
279
|
+
if (mover.isEnabled(particle)) {
|
|
280
|
+
mover.move(particle, delta);
|
|
281
|
+
}
|
|
277
282
|
}
|
|
278
283
|
if (particle.destroyed) {
|
|
279
284
|
particlesToDelete.add(particle);
|
|
@@ -308,7 +313,8 @@ export class Particles {
|
|
|
308
313
|
if (this._needsSort) {
|
|
309
314
|
const zArray = this._zArray;
|
|
310
315
|
zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
|
|
311
|
-
|
|
316
|
+
const lengthOffset = 1;
|
|
317
|
+
this._lastZIndex = zArray[zArray.length - lengthOffset].position.z;
|
|
312
318
|
this._needsSort = false;
|
|
313
319
|
}
|
|
314
320
|
}
|
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 = () => {
|
|
@@ -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
|
}
|
|
@@ -8,12 +8,14 @@ export class InteractionManager {
|
|
|
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
21
|
init() {
|
|
@@ -36,15 +38,21 @@ export class InteractionManager {
|
|
|
36
38
|
interactor.clear(particle, delta);
|
|
37
39
|
}
|
|
38
40
|
for (const interactor of this._particleInteractors) {
|
|
39
|
-
|
|
41
|
+
if (interactor.isEnabled(particle)) {
|
|
42
|
+
await interactor.interact(particle, delta);
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
|
-
|
|
46
|
+
reset(particle) {
|
|
43
47
|
for (const interactor of this._externalInteractors) {
|
|
44
|
-
interactor.isEnabled()
|
|
48
|
+
if (interactor.isEnabled()) {
|
|
49
|
+
interactor.reset(particle);
|
|
50
|
+
}
|
|
45
51
|
}
|
|
46
52
|
for (const interactor of this._particleInteractors) {
|
|
47
|
-
interactor.isEnabled(particle)
|
|
53
|
+
if (interactor.isEnabled(particle)) {
|
|
54
|
+
interactor.reset(particle);
|
|
55
|
+
}
|
|
48
56
|
}
|
|
49
57
|
}
|
|
50
58
|
}
|
|
@@ -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);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { deepExtend } from "../../Utils/Utils.js";
|
|
2
|
+
const defaultPosition = 50;
|
|
2
3
|
export class ManualParticle {
|
|
3
4
|
load(data) {
|
|
4
5
|
if (!data) {
|
|
@@ -6,8 +7,8 @@ export class ManualParticle {
|
|
|
6
7
|
}
|
|
7
8
|
if (data.position) {
|
|
8
9
|
this.position = {
|
|
9
|
-
x: data.position.x ??
|
|
10
|
-
y: data.position.y ??
|
|
10
|
+
x: data.position.x ?? defaultPosition,
|
|
11
|
+
y: data.position.y ?? defaultPosition,
|
|
11
12
|
mode: data.position.mode ?? "percent",
|
|
12
13
|
};
|
|
13
14
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getStyleFromRgb } from "./ColorUtils.js";
|
|
2
|
+
const origin = { x: 0, y: 0 };
|
|
2
3
|
export function drawLine(context, begin, end) {
|
|
3
4
|
context.beginPath();
|
|
4
5
|
context.moveTo(begin.x, begin.y);
|
|
@@ -7,29 +8,28 @@ export function drawLine(context, begin, end) {
|
|
|
7
8
|
}
|
|
8
9
|
export function paintBase(context, dimension, baseColor) {
|
|
9
10
|
context.fillStyle = baseColor ?? "rgba(0,0,0,0)";
|
|
10
|
-
context.fillRect(
|
|
11
|
+
context.fillRect(origin.x, origin.y, dimension.width, dimension.height);
|
|
11
12
|
}
|
|
12
13
|
export function paintImage(context, dimension, image, opacity) {
|
|
13
14
|
if (!image) {
|
|
14
15
|
return;
|
|
15
16
|
}
|
|
16
17
|
context.globalAlpha = opacity;
|
|
17
|
-
context.drawImage(image,
|
|
18
|
+
context.drawImage(image, origin.x, origin.y, dimension.width, dimension.height);
|
|
18
19
|
context.globalAlpha = 1;
|
|
19
20
|
}
|
|
20
21
|
export function clear(context, dimension) {
|
|
21
|
-
context.clearRect(
|
|
22
|
+
context.clearRect(origin.x, origin.y, dimension.width, dimension.height);
|
|
22
23
|
}
|
|
23
24
|
export function drawParticle(data) {
|
|
24
|
-
const { container, context, particle, delta, colorStyles, backgroundMask, composite, radius, opacity, shadow, transform, } = data
|
|
25
|
-
const pos = particle.getPosition(), angle = particle.rotation + (particle.pathRotation ? particle.velocity.angle : 0), rotateData = {
|
|
25
|
+
const { container, context, particle, delta, colorStyles, backgroundMask, composite, radius, opacity, shadow, transform, } = data, pos = particle.getPosition(), defaultAngle = 0, angle = particle.rotation + (particle.pathRotation ? particle.velocity.angle : defaultAngle), rotateData = {
|
|
26
26
|
sin: Math.sin(angle),
|
|
27
27
|
cos: Math.cos(angle),
|
|
28
|
-
}, transformData = {
|
|
29
|
-
a: rotateData.cos * (transform.a ??
|
|
30
|
-
b: rotateData.sin * (transform.b ??
|
|
31
|
-
c: -rotateData.sin * (transform.c ??
|
|
32
|
-
d: rotateData.cos * (transform.d ??
|
|
28
|
+
}, defaultTransformFactor = 1, transformData = {
|
|
29
|
+
a: rotateData.cos * (transform.a ?? defaultTransformFactor),
|
|
30
|
+
b: rotateData.sin * (transform.b ?? defaultTransformFactor),
|
|
31
|
+
c: -rotateData.sin * (transform.c ?? defaultTransformFactor),
|
|
32
|
+
d: rotateData.cos * (transform.d ?? defaultTransformFactor),
|
|
33
33
|
};
|
|
34
34
|
context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
|
|
35
35
|
if (backgroundMask) {
|
|
@@ -45,27 +45,26 @@ export function drawParticle(data) {
|
|
|
45
45
|
if (colorStyles.fill) {
|
|
46
46
|
context.fillStyle = colorStyles.fill;
|
|
47
47
|
}
|
|
48
|
-
const strokeWidth = particle.strokeWidth ??
|
|
48
|
+
const minStrokeWidth = 0, strokeWidth = particle.strokeWidth ?? minStrokeWidth;
|
|
49
49
|
context.lineWidth = strokeWidth;
|
|
50
50
|
if (colorStyles.stroke) {
|
|
51
51
|
context.strokeStyle = colorStyles.stroke;
|
|
52
52
|
}
|
|
53
|
-
const drawData = {
|
|
54
|
-
|
|
53
|
+
const drawData = {
|
|
54
|
+
container,
|
|
55
|
+
context,
|
|
56
|
+
particle,
|
|
57
|
+
radius,
|
|
58
|
+
opacity,
|
|
59
|
+
delta,
|
|
60
|
+
transformData,
|
|
61
|
+
strokeWidth,
|
|
62
|
+
};
|
|
55
63
|
drawShape(drawData);
|
|
56
|
-
if (particle.shapeClose) {
|
|
57
|
-
context.closePath();
|
|
58
|
-
}
|
|
59
|
-
if (strokeWidth > 0) {
|
|
60
|
-
context.stroke();
|
|
61
|
-
}
|
|
62
|
-
if (particle.shapeFill) {
|
|
63
|
-
context.fill();
|
|
64
|
-
}
|
|
65
64
|
drawShapeAfterDraw(drawData);
|
|
66
65
|
drawEffect(drawData);
|
|
67
66
|
context.globalCompositeOperation = "source-over";
|
|
68
|
-
context.
|
|
67
|
+
context.resetTransform();
|
|
69
68
|
}
|
|
70
69
|
export function drawEffect(data) {
|
|
71
70
|
const { container, context, particle, radius, opacity, delta, transformData } = data;
|
|
@@ -87,7 +86,7 @@ export function drawEffect(data) {
|
|
|
87
86
|
});
|
|
88
87
|
}
|
|
89
88
|
export function drawShape(data) {
|
|
90
|
-
const { container, context, particle, radius, opacity, delta, transformData } = data;
|
|
89
|
+
const { container, context, particle, radius, opacity, delta, strokeWidth, transformData } = data, minStrokeWidth = 0;
|
|
91
90
|
if (!particle.shape) {
|
|
92
91
|
return;
|
|
93
92
|
}
|
|
@@ -95,6 +94,7 @@ export function drawShape(data) {
|
|
|
95
94
|
if (!drawer) {
|
|
96
95
|
return;
|
|
97
96
|
}
|
|
97
|
+
context.beginPath();
|
|
98
98
|
drawer.draw({
|
|
99
99
|
context,
|
|
100
100
|
particle,
|
|
@@ -104,6 +104,15 @@ export function drawShape(data) {
|
|
|
104
104
|
pixelRatio: container.retina.pixelRatio,
|
|
105
105
|
transformData: { ...transformData },
|
|
106
106
|
});
|
|
107
|
+
if (particle.shapeClose) {
|
|
108
|
+
context.closePath();
|
|
109
|
+
}
|
|
110
|
+
if (strokeWidth > minStrokeWidth) {
|
|
111
|
+
context.stroke();
|
|
112
|
+
}
|
|
113
|
+
if (particle.shapeFill) {
|
|
114
|
+
context.fill();
|
|
115
|
+
}
|
|
107
116
|
}
|
|
108
117
|
export function drawShapeAfterDraw(data) {
|
|
109
118
|
const { container, context, particle, radius, opacity, delta, transformData } = data;
|
|
@@ -111,7 +120,7 @@ export function drawShapeAfterDraw(data) {
|
|
|
111
120
|
return;
|
|
112
121
|
}
|
|
113
122
|
const drawer = container.shapeDrawers.get(particle.shape);
|
|
114
|
-
if (!drawer
|
|
123
|
+
if (!drawer?.afterDraw) {
|
|
115
124
|
return;
|
|
116
125
|
}
|
|
117
126
|
drawer.afterDraw({
|
|
@@ -137,9 +146,10 @@ export function drawParticlePlugin(context, plugin, particle, delta) {
|
|
|
137
146
|
plugin.drawParticle(context, particle, delta);
|
|
138
147
|
}
|
|
139
148
|
export function alterHsl(color, type, value) {
|
|
149
|
+
const lFactor = 1;
|
|
140
150
|
return {
|
|
141
151
|
h: color.h,
|
|
142
152
|
s: color.s,
|
|
143
|
-
l: color.l + (type === "darken" ? -
|
|
153
|
+
l: color.l + (type === "darken" ? -lFactor : lFactor) * value,
|
|
144
154
|
};
|
|
145
155
|
}
|