@tsparticles/interaction-external-repulse 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/browser/Repulser.js +14 -13
- package/cjs/Repulser.js +13 -12
- package/esm/Repulser.js +14 -13
- package/package.json +2 -2
- package/report.html +2 -2
- package/tsparticles.interaction.external.repulse.js +23 -14
- package/tsparticles.interaction.external.repulse.min.js +1 -1
- package/tsparticles.interaction.external.repulse.min.js.LICENSE.txt +1 -1
- package/types/Types.d.ts +4 -4
- package/umd/Repulser.js +13 -12
package/browser/Repulser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Circle, ExternalInteractorBase, Rectangle, Vector, clamp, divMode, divModeExecute, getDistances, getEasing, isDivModeEnabled, isInArray, mouseMoveEvent, } from "@tsparticles/engine";
|
|
1
|
+
import { Circle, ExternalInteractorBase, Rectangle, Vector, clamp, divMode, divModeExecute, getDistances, getEasing, isDivModeEnabled, isInArray, millisecondsToSeconds, mouseMoveEvent, } from "@tsparticles/engine";
|
|
2
2
|
import { Repulse } from "./Options/Classes/Repulse.js";
|
|
3
|
-
const repulseMode = "repulse";
|
|
3
|
+
const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, half = 0.5;
|
|
4
4
|
export class Repulser extends ExternalInteractorBase {
|
|
5
5
|
constructor(engine, container) {
|
|
6
6
|
super(container);
|
|
@@ -9,7 +9,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
9
9
|
if (!repulseOptions) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
-
const repulse = container.repulse
|
|
12
|
+
const repulse = container.repulse ?? { particles: [] };
|
|
13
13
|
if (!repulse.finish) {
|
|
14
14
|
if (!repulse.count) {
|
|
15
15
|
repulse.count = 0;
|
|
@@ -21,16 +21,16 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
21
21
|
}
|
|
22
22
|
if (repulse.clicking) {
|
|
23
23
|
const repulseDistance = container.retina.repulseModeDistance;
|
|
24
|
-
if (!repulseDistance || repulseDistance <
|
|
24
|
+
if (!repulseDistance || repulseDistance < minDistance) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const repulseRadius = Math.pow(repulseDistance /
|
|
27
|
+
const repulseRadius = Math.pow(repulseDistance / repulseRadiusFactor, repulseRadiusPower), mouseClickPos = container.interactivity.mouse.clickPosition;
|
|
28
28
|
if (mouseClickPos === undefined) {
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
const range = new Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
|
|
32
32
|
for (const particle of query) {
|
|
33
|
-
const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance **
|
|
33
|
+
const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
|
|
34
34
|
if (d <= repulseRadius) {
|
|
35
35
|
repulse.particles.push(particle);
|
|
36
36
|
const vect = Vector.create(dx, dy);
|
|
@@ -48,7 +48,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
48
48
|
};
|
|
49
49
|
this._hoverRepulse = () => {
|
|
50
50
|
const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
|
|
51
|
-
if (!repulseRadius || repulseRadius <
|
|
51
|
+
if (!repulseRadius || repulseRadius < minRadius || !mousePos) {
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
this._processRepulse(mousePos, repulseRadius, new Circle(mousePos.x, mousePos.y, repulseRadius));
|
|
@@ -60,7 +60,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
60
60
|
}
|
|
61
61
|
const { easing, speed, factor, maxSpeed } = repulseOptions, easingFunc = getEasing(easing), velocity = (divRepulse?.speed ?? speed) * factor;
|
|
62
62
|
for (const particle of query) {
|
|
63
|
-
const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(
|
|
63
|
+
const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed), normVec = Vector.create(!distance ? velocity : (dx / distance) * repulseFactor, !distance ? velocity : (dy / distance) * repulseFactor);
|
|
64
64
|
particle.position.addTo(normVec);
|
|
65
65
|
}
|
|
66
66
|
};
|
|
@@ -75,9 +75,9 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
75
75
|
}
|
|
76
76
|
query.forEach((item) => {
|
|
77
77
|
const elem = item, pxRatio = container.retina.pixelRatio, pos = {
|
|
78
|
-
x: (elem.offsetLeft + elem.offsetWidth
|
|
79
|
-
y: (elem.offsetTop + elem.offsetHeight
|
|
80
|
-
}, repulseRadius =
|
|
78
|
+
x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
|
|
79
|
+
y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
|
|
80
|
+
}, repulseRadius = elem.offsetWidth * half * pxRatio, area = div.type === "circle"
|
|
81
81
|
? new Circle(pos.x, pos.y, repulseRadius)
|
|
82
82
|
: new Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), divs = repulse.divs, divRepulse = divMode(divs, elem);
|
|
83
83
|
this._processRepulse(pos, repulseRadius, area, divRepulse);
|
|
@@ -111,7 +111,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
repulse.clicking = false;
|
|
114
|
-
}, repulseOpts.duration *
|
|
114
|
+
}, repulseOpts.duration * millisecondsToSeconds);
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
clear() {
|
|
@@ -134,10 +134,11 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
134
134
|
else {
|
|
135
135
|
divModeExecute(repulseMode, divs, (selector, div) => this._singleSelectorRepulse(selector, div));
|
|
136
136
|
}
|
|
137
|
+
await Promise.resolve();
|
|
137
138
|
}
|
|
138
139
|
isEnabled(particle) {
|
|
139
140
|
const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = (particle?.interactivity ?? options.interactivity).events, divs = events.onDiv, hover = events.onHover, click = events.onClick, divRepulse = isDivModeEnabled(repulseMode, divs);
|
|
140
|
-
if (!(divRepulse || (hover.enable && mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
141
|
+
if (!(divRepulse || (hover.enable && !!mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
141
142
|
return false;
|
|
142
143
|
}
|
|
143
144
|
const hoverMode = hover.mode, clickMode = click.mode;
|
package/cjs/Repulser.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Repulser = void 0;
|
|
4
4
|
const engine_1 = require("@tsparticles/engine");
|
|
5
5
|
const Repulse_js_1 = require("./Options/Classes/Repulse.js");
|
|
6
|
-
const repulseMode = "repulse";
|
|
6
|
+
const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, half = 0.5;
|
|
7
7
|
class Repulser extends engine_1.ExternalInteractorBase {
|
|
8
8
|
constructor(engine, container) {
|
|
9
9
|
super(container);
|
|
@@ -12,7 +12,7 @@ class Repulser extends engine_1.ExternalInteractorBase {
|
|
|
12
12
|
if (!repulseOptions) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
-
const repulse = container.repulse
|
|
15
|
+
const repulse = container.repulse ?? { particles: [] };
|
|
16
16
|
if (!repulse.finish) {
|
|
17
17
|
if (!repulse.count) {
|
|
18
18
|
repulse.count = 0;
|
|
@@ -24,16 +24,16 @@ class Repulser extends engine_1.ExternalInteractorBase {
|
|
|
24
24
|
}
|
|
25
25
|
if (repulse.clicking) {
|
|
26
26
|
const repulseDistance = container.retina.repulseModeDistance;
|
|
27
|
-
if (!repulseDistance || repulseDistance <
|
|
27
|
+
if (!repulseDistance || repulseDistance < minDistance) {
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
const repulseRadius = Math.pow(repulseDistance /
|
|
30
|
+
const repulseRadius = Math.pow(repulseDistance / repulseRadiusFactor, repulseRadiusPower), mouseClickPos = container.interactivity.mouse.clickPosition;
|
|
31
31
|
if (mouseClickPos === undefined) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
const range = new engine_1.Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
|
|
35
35
|
for (const particle of query) {
|
|
36
|
-
const { dx, dy, distance } = (0, engine_1.getDistances)(mouseClickPos, particle.position), d = distance **
|
|
36
|
+
const { dx, dy, distance } = (0, engine_1.getDistances)(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
|
|
37
37
|
if (d <= repulseRadius) {
|
|
38
38
|
repulse.particles.push(particle);
|
|
39
39
|
const vect = engine_1.Vector.create(dx, dy);
|
|
@@ -51,7 +51,7 @@ class Repulser extends engine_1.ExternalInteractorBase {
|
|
|
51
51
|
};
|
|
52
52
|
this._hoverRepulse = () => {
|
|
53
53
|
const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
|
|
54
|
-
if (!repulseRadius || repulseRadius <
|
|
54
|
+
if (!repulseRadius || repulseRadius < minRadius || !mousePos) {
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
this._processRepulse(mousePos, repulseRadius, new engine_1.Circle(mousePos.x, mousePos.y, repulseRadius));
|
|
@@ -63,7 +63,7 @@ class Repulser extends engine_1.ExternalInteractorBase {
|
|
|
63
63
|
}
|
|
64
64
|
const { easing, speed, factor, maxSpeed } = repulseOptions, easingFunc = (0, engine_1.getEasing)(easing), velocity = (divRepulse?.speed ?? speed) * factor;
|
|
65
65
|
for (const particle of query) {
|
|
66
|
-
const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position), repulseFactor = (0, engine_1.clamp)(easingFunc(
|
|
66
|
+
const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position), repulseFactor = (0, engine_1.clamp)(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed), normVec = engine_1.Vector.create(!distance ? velocity : (dx / distance) * repulseFactor, !distance ? velocity : (dy / distance) * repulseFactor);
|
|
67
67
|
particle.position.addTo(normVec);
|
|
68
68
|
}
|
|
69
69
|
};
|
|
@@ -78,9 +78,9 @@ class Repulser extends engine_1.ExternalInteractorBase {
|
|
|
78
78
|
}
|
|
79
79
|
query.forEach((item) => {
|
|
80
80
|
const elem = item, pxRatio = container.retina.pixelRatio, pos = {
|
|
81
|
-
x: (elem.offsetLeft + elem.offsetWidth
|
|
82
|
-
y: (elem.offsetTop + elem.offsetHeight
|
|
83
|
-
}, repulseRadius =
|
|
81
|
+
x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
|
|
82
|
+
y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
|
|
83
|
+
}, repulseRadius = elem.offsetWidth * half * pxRatio, area = div.type === "circle"
|
|
84
84
|
? new engine_1.Circle(pos.x, pos.y, repulseRadius)
|
|
85
85
|
: new engine_1.Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), divs = repulse.divs, divRepulse = (0, engine_1.divMode)(divs, elem);
|
|
86
86
|
this._processRepulse(pos, repulseRadius, area, divRepulse);
|
|
@@ -114,7 +114,7 @@ class Repulser extends engine_1.ExternalInteractorBase {
|
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
116
116
|
repulse.clicking = false;
|
|
117
|
-
}, repulseOpts.duration *
|
|
117
|
+
}, repulseOpts.duration * engine_1.millisecondsToSeconds);
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
120
|
clear() {
|
|
@@ -137,10 +137,11 @@ class Repulser extends engine_1.ExternalInteractorBase {
|
|
|
137
137
|
else {
|
|
138
138
|
(0, engine_1.divModeExecute)(repulseMode, divs, (selector, div) => this._singleSelectorRepulse(selector, div));
|
|
139
139
|
}
|
|
140
|
+
await Promise.resolve();
|
|
140
141
|
}
|
|
141
142
|
isEnabled(particle) {
|
|
142
143
|
const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = (particle?.interactivity ?? options.interactivity).events, divs = events.onDiv, hover = events.onHover, click = events.onClick, divRepulse = (0, engine_1.isDivModeEnabled)(repulseMode, divs);
|
|
143
|
-
if (!(divRepulse || (hover.enable && mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
144
|
+
if (!(divRepulse || (hover.enable && !!mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
144
145
|
return false;
|
|
145
146
|
}
|
|
146
147
|
const hoverMode = hover.mode, clickMode = click.mode;
|
package/esm/Repulser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Circle, ExternalInteractorBase, Rectangle, Vector, clamp, divMode, divModeExecute, getDistances, getEasing, isDivModeEnabled, isInArray, mouseMoveEvent, } from "@tsparticles/engine";
|
|
1
|
+
import { Circle, ExternalInteractorBase, Rectangle, Vector, clamp, divMode, divModeExecute, getDistances, getEasing, isDivModeEnabled, isInArray, millisecondsToSeconds, mouseMoveEvent, } from "@tsparticles/engine";
|
|
2
2
|
import { Repulse } from "./Options/Classes/Repulse.js";
|
|
3
|
-
const repulseMode = "repulse";
|
|
3
|
+
const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, half = 0.5;
|
|
4
4
|
export class Repulser extends ExternalInteractorBase {
|
|
5
5
|
constructor(engine, container) {
|
|
6
6
|
super(container);
|
|
@@ -9,7 +9,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
9
9
|
if (!repulseOptions) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
-
const repulse = container.repulse
|
|
12
|
+
const repulse = container.repulse ?? { particles: [] };
|
|
13
13
|
if (!repulse.finish) {
|
|
14
14
|
if (!repulse.count) {
|
|
15
15
|
repulse.count = 0;
|
|
@@ -21,16 +21,16 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
21
21
|
}
|
|
22
22
|
if (repulse.clicking) {
|
|
23
23
|
const repulseDistance = container.retina.repulseModeDistance;
|
|
24
|
-
if (!repulseDistance || repulseDistance <
|
|
24
|
+
if (!repulseDistance || repulseDistance < minDistance) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const repulseRadius = Math.pow(repulseDistance /
|
|
27
|
+
const repulseRadius = Math.pow(repulseDistance / repulseRadiusFactor, repulseRadiusPower), mouseClickPos = container.interactivity.mouse.clickPosition;
|
|
28
28
|
if (mouseClickPos === undefined) {
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
const range = new Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
|
|
32
32
|
for (const particle of query) {
|
|
33
|
-
const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance **
|
|
33
|
+
const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
|
|
34
34
|
if (d <= repulseRadius) {
|
|
35
35
|
repulse.particles.push(particle);
|
|
36
36
|
const vect = Vector.create(dx, dy);
|
|
@@ -48,7 +48,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
48
48
|
};
|
|
49
49
|
this._hoverRepulse = () => {
|
|
50
50
|
const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
|
|
51
|
-
if (!repulseRadius || repulseRadius <
|
|
51
|
+
if (!repulseRadius || repulseRadius < minRadius || !mousePos) {
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
this._processRepulse(mousePos, repulseRadius, new Circle(mousePos.x, mousePos.y, repulseRadius));
|
|
@@ -60,7 +60,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
60
60
|
}
|
|
61
61
|
const { easing, speed, factor, maxSpeed } = repulseOptions, easingFunc = getEasing(easing), velocity = (divRepulse?.speed ?? speed) * factor;
|
|
62
62
|
for (const particle of query) {
|
|
63
|
-
const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(
|
|
63
|
+
const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed), normVec = Vector.create(!distance ? velocity : (dx / distance) * repulseFactor, !distance ? velocity : (dy / distance) * repulseFactor);
|
|
64
64
|
particle.position.addTo(normVec);
|
|
65
65
|
}
|
|
66
66
|
};
|
|
@@ -75,9 +75,9 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
75
75
|
}
|
|
76
76
|
query.forEach((item) => {
|
|
77
77
|
const elem = item, pxRatio = container.retina.pixelRatio, pos = {
|
|
78
|
-
x: (elem.offsetLeft + elem.offsetWidth
|
|
79
|
-
y: (elem.offsetTop + elem.offsetHeight
|
|
80
|
-
}, repulseRadius =
|
|
78
|
+
x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
|
|
79
|
+
y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
|
|
80
|
+
}, repulseRadius = elem.offsetWidth * half * pxRatio, area = div.type === "circle"
|
|
81
81
|
? new Circle(pos.x, pos.y, repulseRadius)
|
|
82
82
|
: new Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), divs = repulse.divs, divRepulse = divMode(divs, elem);
|
|
83
83
|
this._processRepulse(pos, repulseRadius, area, divRepulse);
|
|
@@ -111,7 +111,7 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
repulse.clicking = false;
|
|
114
|
-
}, repulseOpts.duration *
|
|
114
|
+
}, repulseOpts.duration * millisecondsToSeconds);
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
clear() {
|
|
@@ -134,10 +134,11 @@ export class Repulser extends ExternalInteractorBase {
|
|
|
134
134
|
else {
|
|
135
135
|
divModeExecute(repulseMode, divs, (selector, div) => this._singleSelectorRepulse(selector, div));
|
|
136
136
|
}
|
|
137
|
+
await Promise.resolve();
|
|
137
138
|
}
|
|
138
139
|
isEnabled(particle) {
|
|
139
140
|
const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = (particle?.interactivity ?? options.interactivity).events, divs = events.onDiv, hover = events.onHover, click = events.onClick, divRepulse = isDivModeEnabled(repulseMode, divs);
|
|
140
|
-
if (!(divRepulse || (hover.enable && mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
141
|
+
if (!(divRepulse || (hover.enable && !!mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
141
142
|
return false;
|
|
142
143
|
}
|
|
143
144
|
const hoverMode = hover.mode, clickMode = click.mode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsparticles/interaction-external-repulse",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "tsParticles repulse external interaction",
|
|
5
5
|
"homepage": "https://particles.js.org",
|
|
6
6
|
"repository": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"./package.json": "./package.json"
|
|
88
88
|
},
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"@tsparticles/engine": "^3.0
|
|
90
|
+
"@tsparticles/engine": "^3.1.0"
|
|
91
91
|
},
|
|
92
92
|
"publishConfig": {
|
|
93
93
|
"access": "public"
|
package/report.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8"/>
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
6
|
-
<title>@tsparticles/interaction-external-repulse [
|
|
6
|
+
<title>@tsparticles/interaction-external-repulse [13 Jan 2024 at 23:00]</title>
|
|
7
7
|
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABrVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+O1foceMD///+J0/qK1Pr7/v8Xdr/9///W8P4UdL7L7P0Scr2r4Pyj3vwad8D5/f/2/f+55f3E6f34+/2H0/ojfMKpzOd0rNgQcb3F3O/j9f7c8v6g3Pz0/P/w+v/q+P7n9v6T1/uQ1vuE0vqLut/y+v+Z2fvt+f+15Pzv9fuc2/vR7v2V2Pvd6/bg9P7I6/285/2y4/yp3/zp8vk8i8kqgMT7/P31+fyv4vxGkcz6/P6/6P3j7vfS5PNnpNUxhcbO7f7F6v3O4vHK3/DA2u631Ouy0eqXweKJud5wqthfoNMMbLvY8f73+v2dxeR8sNtTmdDx9/zX6PSjyeaCtd1YnNGX2PuQveCGt95Nls42h8dLlM3F4vBtAAAAM3RSTlMAAyOx0/sKBvik8opWGBMOAe3l1snDm2E9LSb06eHcu5JpHbarfHZCN9CBb08zzkdNS0kYaptYAAAFV0lEQVRYw92X51/aYBDHHS2O2qqttVbrqNq9m+TJIAYIShBkWwqIiCgoWvfeq7Z2/s29hyQNyUcR7LveGwVyXy6XH8/9rqxglLfUPLxVduUor3h0rfp2TYvpivk37929TkG037hffoX0+peVtZQc1589rigVUdXS/ABSAyEmGIO/1XfvldSK8vs3OqB6u3m0nxmIrvgB0dj7rr7Y9IbuF68hnfFaiHA/sxqm0wciIG43P60qKv9WXWc1RXGh/mFESFABTSBi0sNAKzqet17eCtOb3kZIDwxEEU0oAIJGYxNBDhBND29e0rtXXbcpuPmED9IhEAAQ/AXEaF8EPmnrrKsv0LvWR3fg5sWDNAFZOgAgaKvZDogHNU9MFwnnYROkc56RD5CjAbQX9Ow4g7upCsvYu55aSI/Nj0H1akgKQEUM94dwK65hYRmFU9MIcH/fqJYOZYcnuJSU/waKDgTOEVaVKhwrTRP5XzgSpAITYzom7UvkhFX5VutmxeNnWDjjswTKTyfgluNDGbUpWissXhF3s7mlSml+czWkg3D0l1nNjGNjz3myOQOa1KM/jOS6ebdbAVTCi4gljHSFrviza7tOgRWcS0MOUX9zdNgag5w7rRqA44Lzw0hr1WqES36dFliSJFlh2rXIae3FFcDDgKdxrUIDePr8jGcSClV1u7A9xeN0ModY/pHMxmR1EzRh8TJiwqsHmKW0l4FCEZI+jHio+JdPPE9qwQtTRxku2D8sIeRL2LnxWSllANCQGOIiqVHAz2ye2JR0DcH+HoxDkaADLjgxjKQ+AwCX/g0+DNgdG0ukYCONAe+dbc2IAc6fwt1ARoDSezNHxV2Cmzwv3O6lDMV55edBGwGK9n1+x2F8EDfAGCxug8MhpsMEcTEAWf3rx2vZhe/LAmtIn/6apE6PN0ULKgywD9mmdxbmFl3OvD5AS5fW5zLbv/YHmcsBTjf/afDz3MaZTVCfAP9z6/Bw6ycv8EUBWJIn9zYcoAWWlW9+OzO3vkTy8H+RANLmdrpOuYWdZYEXpo+TlCJrW5EARb7fF+bWdqf3hhyZI1nWJQHgznErZhbjoEsWqi8dQNoE294aldzFurwSABL2XXMf9+H1VQGke9exw5P/AnA5Pv5ngMul7LOvO922iwACu8WkCwLCafvM4CeWPxfA8lNHcWZSoi8EwMAIciKX2Z4SWCMAa3snCZ/G4EA8D6CMLNFsGQhkkz/gQNEBbPCbWsxGUpYVu3z8IyNAknwJkfPMEhLyrdi5RTyUVACkw4GSFRNWJNEW+fgPGwHD8/JxnRuLabN4CGNRkAE23na2+VmEAUmrYymSGjMAYqH84YUIyzgzs3XC7gNgH36Vcc4zKY9o9fgPBXUAiHHwVboBHGLiX6Zcjp1f2wu4tvzZKo0ecPnDtQYDQvJXaBeNzce45Fp28ZQLrEZVuFqgBwOalArKXnW1UzlnSusQKJqKYNuz4tOnI6sZG4zanpemv+7ySU2jbA9h6uhcgpfy6G2PahirDZ6zvq6zDduMVFTKvzw8wgyEdelwY9in3XkEPs3osJuwRQ4qTkfzifndg9Gfc4pdsu82+tTnHZTBa2EAMrqr2t43pguc8tNm7JQVQ2S0ukj2d22dhXYP0/veWtwKrCkNoNimAN5+Xr/oLrxswKbVJjteWrX7eR63o4j9q0GxnaBdWgGA5VStpanIjQmEhV0/nVt5VOFUvix6awJhPcAaTEShgrG+iGyvb5a0Ndb1YGHFPEwoqAinoaykaID1o1pdPNu7XsnCKQ3R+hwWIIhGvORcJUBYXe3Xa3vq/mF/N9V13ugufMkfXn+KHsRD0B8AAAAASUVORK5CYII=" type="image/x-icon" />
|
|
8
8
|
|
|
9
9
|
<script>
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<body>
|
|
32
32
|
<div id="app"></div>
|
|
33
33
|
<script>
|
|
34
|
-
window.chartData = [{"label":"tsparticles.interaction.external.repulse.js","isAsset":true,"statSize":
|
|
34
|
+
window.chartData = [{"label":"tsparticles.interaction.external.repulse.js","isAsset":true,"statSize":9869,"parsedSize":13762,"gzipSize":3443,"groups":[{"label":"dist/browser","path":"./dist/browser","statSize":9827,"groups":[{"id":89,"label":"index.js + 4 modules (concatenated)","path":"./dist/browser/index.js + 4 modules (concatenated)","statSize":9827,"parsedSize":13762,"gzipSize":3443,"concatenated":true,"groups":[{"label":"dist/browser","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser","statSize":9827,"groups":[{"id":null,"label":"index.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/index.js","statSize":528,"parsedSize":739,"gzipSize":184,"inaccurateSizes":true},{"id":null,"label":"Repulser.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/Repulser.js","statSize":7826,"parsedSize":10959,"gzipSize":2741,"inaccurateSizes":true},{"label":"Options/Classes","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/Options/Classes","statSize":1473,"groups":[{"id":null,"label":"Repulse.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/Options/Classes/Repulse.js","statSize":426,"parsedSize":596,"gzipSize":149,"inaccurateSizes":true},{"id":null,"label":"RepulseBase.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/Options/Classes/RepulseBase.js","statSize":729,"parsedSize":1020,"gzipSize":255,"inaccurateSizes":true},{"id":null,"label":"RepulseDiv.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/Options/Classes/RepulseDiv.js","statSize":318,"parsedSize":445,"gzipSize":111,"inaccurateSizes":true}],"parsedSize":2062,"gzipSize":516,"inaccurateSizes":true}],"parsedSize":13762,"gzipSize":3443,"inaccurateSizes":true}]}],"parsedSize":13762,"gzipSize":3443},{"label":"engine\",\"commonjs2\":\"@tsparticles/engine\",\"amd\":\"@tsparticles","path":"./engine\",\"commonjs2\":\"@tsparticles/engine\",\"amd\":\"@tsparticles","statSize":42,"groups":[{"id":533,"label":"engine\",\"root\":\"window\"}","path":"./engine\",\"commonjs2\":\"@tsparticles/engine\",\"amd\":\"@tsparticles/engine\",\"root\":\"window\"}","statSize":42}],"parsedSize":0,"gzipSize":0}],"isInitialByEntrypoint":{"tsparticles.interaction.external.repulse":true}}];
|
|
35
35
|
window.entrypoints = ["tsparticles.interaction.external.repulse","tsparticles.interaction.external.repulse.min"];
|
|
36
36
|
window.defaultSizes = "parsed";
|
|
37
37
|
</script>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Demo / Generator : https://particles.js.org/
|
|
5
5
|
* GitHub : https://www.github.com/matteobruni/tsparticles
|
|
6
6
|
* How to use? : Check the GitHub README
|
|
7
|
-
* v3.0
|
|
7
|
+
* v3.1.0
|
|
8
8
|
*/
|
|
9
9
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
10
10
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
@@ -170,7 +170,15 @@ class Repulse extends RepulseBase {
|
|
|
170
170
|
;// CONCATENATED MODULE: ./dist/browser/Repulser.js
|
|
171
171
|
|
|
172
172
|
|
|
173
|
-
const repulseMode = "repulse"
|
|
173
|
+
const repulseMode = "repulse",
|
|
174
|
+
minDistance = 0,
|
|
175
|
+
repulseRadiusFactor = 6,
|
|
176
|
+
repulseRadiusPower = 3,
|
|
177
|
+
squarePower = 2,
|
|
178
|
+
minRadius = 0,
|
|
179
|
+
minSpeed = 0,
|
|
180
|
+
easingOffset = 1,
|
|
181
|
+
half = 0.5;
|
|
174
182
|
class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
175
183
|
constructor(engine, container) {
|
|
176
184
|
super(container);
|
|
@@ -180,7 +188,7 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
180
188
|
if (!repulseOptions) {
|
|
181
189
|
return;
|
|
182
190
|
}
|
|
183
|
-
const repulse = container.repulse
|
|
191
|
+
const repulse = container.repulse ?? {
|
|
184
192
|
particles: []
|
|
185
193
|
};
|
|
186
194
|
if (!repulse.finish) {
|
|
@@ -194,10 +202,10 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
194
202
|
}
|
|
195
203
|
if (repulse.clicking) {
|
|
196
204
|
const repulseDistance = container.retina.repulseModeDistance;
|
|
197
|
-
if (!repulseDistance || repulseDistance <
|
|
205
|
+
if (!repulseDistance || repulseDistance < minDistance) {
|
|
198
206
|
return;
|
|
199
207
|
}
|
|
200
|
-
const repulseRadius = Math.pow(repulseDistance /
|
|
208
|
+
const repulseRadius = Math.pow(repulseDistance / repulseRadiusFactor, repulseRadiusPower),
|
|
201
209
|
mouseClickPos = container.interactivity.mouse.clickPosition;
|
|
202
210
|
if (mouseClickPos === undefined) {
|
|
203
211
|
return;
|
|
@@ -210,7 +218,7 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
210
218
|
dy,
|
|
211
219
|
distance
|
|
212
220
|
} = (0,engine_root_window_.getDistances)(mouseClickPos, particle.position),
|
|
213
|
-
d = distance **
|
|
221
|
+
d = distance ** squarePower,
|
|
214
222
|
velocity = repulseOptions.speed,
|
|
215
223
|
force = -repulseRadius * velocity / d;
|
|
216
224
|
if (d <= repulseRadius) {
|
|
@@ -231,7 +239,7 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
231
239
|
const container = this.container,
|
|
232
240
|
mousePos = container.interactivity.mouse.position,
|
|
233
241
|
repulseRadius = container.retina.repulseModeDistance;
|
|
234
|
-
if (!repulseRadius || repulseRadius <
|
|
242
|
+
if (!repulseRadius || repulseRadius < minRadius || !mousePos) {
|
|
235
243
|
return;
|
|
236
244
|
}
|
|
237
245
|
this._processRepulse(mousePos, repulseRadius, new engine_root_window_.Circle(mousePos.x, mousePos.y, repulseRadius));
|
|
@@ -257,8 +265,8 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
257
265
|
dy,
|
|
258
266
|
distance
|
|
259
267
|
} = (0,engine_root_window_.getDistances)(particle.position, position),
|
|
260
|
-
repulseFactor = (0,engine_root_window_.clamp)(easingFunc(
|
|
261
|
-
normVec = engine_root_window_.Vector.create(distance
|
|
268
|
+
repulseFactor = (0,engine_root_window_.clamp)(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed),
|
|
269
|
+
normVec = engine_root_window_.Vector.create(!distance ? velocity : dx / distance * repulseFactor, !distance ? velocity : dy / distance * repulseFactor);
|
|
262
270
|
particle.position.addTo(normVec);
|
|
263
271
|
}
|
|
264
272
|
};
|
|
@@ -276,10 +284,10 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
276
284
|
const elem = item,
|
|
277
285
|
pxRatio = container.retina.pixelRatio,
|
|
278
286
|
pos = {
|
|
279
|
-
x: (elem.offsetLeft + elem.offsetWidth
|
|
280
|
-
y: (elem.offsetTop + elem.offsetHeight
|
|
287
|
+
x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
|
|
288
|
+
y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio
|
|
281
289
|
},
|
|
282
|
-
repulseRadius = elem.offsetWidth
|
|
290
|
+
repulseRadius = elem.offsetWidth * half * pxRatio,
|
|
283
291
|
area = div.type === "circle" ? new engine_root_window_.Circle(pos.x, pos.y, repulseRadius) : new engine_root_window_.Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio),
|
|
284
292
|
divs = repulse.divs,
|
|
285
293
|
divRepulse = (0,engine_root_window_.divMode)(divs, elem);
|
|
@@ -319,7 +327,7 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
319
327
|
return;
|
|
320
328
|
}
|
|
321
329
|
repulse.clicking = false;
|
|
322
|
-
}, repulseOpts.duration *
|
|
330
|
+
}, repulseOpts.duration * engine_root_window_.millisecondsToSeconds);
|
|
323
331
|
};
|
|
324
332
|
}
|
|
325
333
|
clear() {}
|
|
@@ -350,6 +358,7 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
350
358
|
} else {
|
|
351
359
|
(0,engine_root_window_.divModeExecute)(repulseMode, divs, (selector, div) => this._singleSelectorRepulse(selector, div));
|
|
352
360
|
}
|
|
361
|
+
await Promise.resolve();
|
|
353
362
|
}
|
|
354
363
|
isEnabled(particle) {
|
|
355
364
|
const container = this.container,
|
|
@@ -360,7 +369,7 @@ class Repulser extends engine_root_window_.ExternalInteractorBase {
|
|
|
360
369
|
hover = events.onHover,
|
|
361
370
|
click = events.onClick,
|
|
362
371
|
divRepulse = (0,engine_root_window_.isDivModeEnabled)(repulseMode, divs);
|
|
363
|
-
if (!(divRepulse || hover.enable && mouse.position || click.enable && mouse.clickPosition)) {
|
|
372
|
+
if (!(divRepulse || hover.enable && !!mouse.position || click.enable && mouse.clickPosition)) {
|
|
364
373
|
return false;
|
|
365
374
|
}
|
|
366
375
|
const hoverMode = hover.mode,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see tsparticles.interaction.external.repulse.min.js.LICENSE.txt */
|
|
2
|
-
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("@tsparticles/engine"));else if("function"==typeof define&&define.amd)define(["@tsparticles/engine"],t);else{var i="object"==typeof exports?t(require("@tsparticles/engine")):t(e.window);for(var s in i)("object"==typeof exports?exports:e)[s]=i[s]}}(this,(e=>(()=>{"use strict";var t={533:t=>{t.exports=e}},i={};function s(e){var o=i[e];if(void 0!==o)return o.exports;var n=i[e]={exports:{}};return t[e](n,n.exports,s),n.exports}s.d=(e,t)=>{for(var i in t)s.o(t,i)&&!s.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{s.r(o),s.d(o,{Repulse:()=>n,RepulseBase:()=>t,RepulseDiv:()=>i,loadExternalRepulseInteraction:()=>a});var e=s(533);class t{constructor(){this.distance=200,this.duration=.4,this.factor=100,this.speed=1,this.maxSpeed=50,this.easing="ease-out-quad"}load(e){e&&(void 0!==e.distance&&(this.distance=e.distance),void 0!==e.duration&&(this.duration=e.duration),void 0!==e.easing&&(this.easing=e.easing),void 0!==e.factor&&(this.factor=e.factor),void 0!==e.speed&&(this.speed=e.speed),void 0!==e.maxSpeed&&(this.maxSpeed=e.maxSpeed))}}class i extends t{constructor(){super(),this.selectors=[]}load(e){super.load(e),e&&void 0!==e.selectors&&(this.selectors=e.selectors)}}class n extends t{load(t){super.load(t),t&&(this.divs=(0,e.executeOnSingleOrMultiple)(t.divs,(e=>{const t=new i;return t.load(e),t})))}}const r="repulse";class c extends e.ExternalInteractorBase{constructor(t,i){super(i),this._clickRepulse=()=>{const t=this.container,i=t.actualOptions.interactivity.modes.repulse;if(!i)return;const s=t.repulse
|
|
2
|
+
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("@tsparticles/engine"));else if("function"==typeof define&&define.amd)define(["@tsparticles/engine"],t);else{var i="object"==typeof exports?t(require("@tsparticles/engine")):t(e.window);for(var s in i)("object"==typeof exports?exports:e)[s]=i[s]}}(this,(e=>(()=>{"use strict";var t={533:t=>{t.exports=e}},i={};function s(e){var o=i[e];if(void 0!==o)return o.exports;var n=i[e]={exports:{}};return t[e](n,n.exports,s),n.exports}s.d=(e,t)=>{for(var i in t)s.o(t,i)&&!s.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{s.r(o),s.d(o,{Repulse:()=>n,RepulseBase:()=>t,RepulseDiv:()=>i,loadExternalRepulseInteraction:()=>a});var e=s(533);class t{constructor(){this.distance=200,this.duration=.4,this.factor=100,this.speed=1,this.maxSpeed=50,this.easing="ease-out-quad"}load(e){e&&(void 0!==e.distance&&(this.distance=e.distance),void 0!==e.duration&&(this.duration=e.duration),void 0!==e.easing&&(this.easing=e.easing),void 0!==e.factor&&(this.factor=e.factor),void 0!==e.speed&&(this.speed=e.speed),void 0!==e.maxSpeed&&(this.maxSpeed=e.maxSpeed))}}class i extends t{constructor(){super(),this.selectors=[]}load(e){super.load(e),e&&void 0!==e.selectors&&(this.selectors=e.selectors)}}class n extends t{load(t){super.load(t),t&&(this.divs=(0,e.executeOnSingleOrMultiple)(t.divs,(e=>{const t=new i;return t.load(e),t})))}}const r="repulse";class c extends e.ExternalInteractorBase{constructor(t,i){super(i),this._clickRepulse=()=>{const t=this.container,i=t.actualOptions.interactivity.modes.repulse;if(!i)return;const s=t.repulse??{particles:[]};if(s.finish||(s.count||(s.count=0),s.count++,s.count===t.particles.count&&(s.finish=!0)),s.clicking){const o=t.retina.repulseModeDistance;if(!o||o<0)return;const n=Math.pow(o/6,3),r=t.interactivity.mouse.clickPosition;if(void 0===r)return;const c=new e.Circle(r.x,r.y,n),a=t.particles.quadTree.query(c,(e=>this.isEnabled(e)));for(const t of a){const{dx:o,dy:c,distance:a}=(0,e.getDistances)(r,t.position),l=a**2,p=-n*i.speed/l;if(l<=n){s.particles.push(t);const i=e.Vector.create(o,c);i.length=p,t.velocity.setTo(i)}}}else if(!1===s.clicking){for(const e of s.particles)e.velocity.setTo(e.initialVelocity);s.particles=[]}},this._hoverRepulse=()=>{const t=this.container,i=t.interactivity.mouse.position,s=t.retina.repulseModeDistance;!s||s<0||!i||this._processRepulse(i,s,new e.Circle(i.x,i.y,s))},this._processRepulse=(t,i,s,o)=>{const n=this.container,r=n.particles.quadTree.query(s,(e=>this.isEnabled(e))),c=n.actualOptions.interactivity.modes.repulse;if(!c)return;const{easing:a,speed:l,factor:p,maxSpeed:d}=c,u=(0,e.getEasing)(a),f=(o?.speed??l)*p;for(const s of r){const{dx:o,dy:n,distance:r}=(0,e.getDistances)(s.position,t),c=(0,e.clamp)(u(1-r/i)*f,0,d),a=e.Vector.create(r?o/r*c:f,r?n/r*c:f);s.position.addTo(a)}},this._singleSelectorRepulse=(t,i)=>{const s=this.container,o=s.actualOptions.interactivity.modes.repulse;if(!o)return;const n=document.querySelectorAll(t);n.length&&n.forEach((t=>{const n=t,r=s.retina.pixelRatio,c={x:(n.offsetLeft+.5*n.offsetWidth)*r,y:(n.offsetTop+.5*n.offsetHeight)*r},a=.5*n.offsetWidth*r,l="circle"===i.type?new e.Circle(c.x,c.y,a):new e.Rectangle(n.offsetLeft*r,n.offsetTop*r,n.offsetWidth*r,n.offsetHeight*r),p=o.divs,d=(0,e.divMode)(p,n);this._processRepulse(c,a,l,d)}))},this._engine=t,i.repulse||(i.repulse={particles:[]}),this.handleClickMode=t=>{const s=this.container.actualOptions.interactivity.modes.repulse;if(!s||t!==r)return;i.repulse||(i.repulse={particles:[]});const o=i.repulse;o.clicking=!0,o.count=0;for(const e of i.repulse.particles)this.isEnabled(e)&&e.velocity.setTo(e.initialVelocity);o.particles=[],o.finish=!1,setTimeout((()=>{i.destroyed||(o.clicking=!1)}),s.duration*e.millisecondsToSeconds)}}clear(){}init(){const e=this.container,t=e.actualOptions.interactivity.modes.repulse;t&&(e.retina.repulseModeDistance=t.distance*e.retina.pixelRatio)}async interact(){const t=this.container,i=t.actualOptions,s=t.interactivity.status===e.mouseMoveEvent,o=i.interactivity.events,n=o.onHover,c=n.enable,a=n.mode,l=o.onClick,p=l.enable,d=l.mode,u=o.onDiv;s&&c&&(0,e.isInArray)(r,a)?this._hoverRepulse():p&&(0,e.isInArray)(r,d)?this._clickRepulse():(0,e.divModeExecute)(r,u,((e,t)=>this._singleSelectorRepulse(e,t))),await Promise.resolve()}isEnabled(t){const i=this.container,s=i.actualOptions,o=i.interactivity.mouse,n=(t?.interactivity??s.interactivity).events,c=n.onDiv,a=n.onHover,l=n.onClick,p=(0,e.isDivModeEnabled)(r,c);if(!(p||a.enable&&o.position||l.enable&&o.clickPosition))return!1;const d=a.mode,u=l.mode;return(0,e.isInArray)(r,d)||(0,e.isInArray)(r,u)||p}loadModeOptions(e,...t){e.repulse||(e.repulse=new n);for(const i of t)e.repulse.load(i?.repulse)}reset(){}}async function a(e,t=!0){await e.addInteractor("externalRepulse",(t=>new c(e,t)),t)}})(),o})()));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! tsParticles Repulse External Interaction v3.0
|
|
1
|
+
/*! tsParticles Repulse External Interaction v3.1.0 by Matteo Bruni */
|
package/types/Types.d.ts
CHANGED
|
@@ -2,12 +2,12 @@ import type { Container, Particle } from "@tsparticles/engine";
|
|
|
2
2
|
import type { IRepulse } from "./Options/Interfaces/IRepulse.js";
|
|
3
3
|
import type { Repulse } from "./Options/Classes/Repulse.js";
|
|
4
4
|
import type { RepulseOptions } from "./Options/Classes/RepulseOptions.js";
|
|
5
|
-
export
|
|
5
|
+
export interface IRepulseMode {
|
|
6
6
|
repulse: IRepulse;
|
|
7
|
-
}
|
|
8
|
-
export
|
|
7
|
+
}
|
|
8
|
+
export interface RepulseMode {
|
|
9
9
|
repulse?: Repulse;
|
|
10
|
-
}
|
|
10
|
+
}
|
|
11
11
|
interface IContainerRepulse {
|
|
12
12
|
clicking?: boolean;
|
|
13
13
|
count?: number;
|
package/umd/Repulser.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
exports.Repulser = void 0;
|
|
13
13
|
const engine_1 = require("@tsparticles/engine");
|
|
14
14
|
const Repulse_js_1 = require("./Options/Classes/Repulse.js");
|
|
15
|
-
const repulseMode = "repulse";
|
|
15
|
+
const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, half = 0.5;
|
|
16
16
|
class Repulser extends engine_1.ExternalInteractorBase {
|
|
17
17
|
constructor(engine, container) {
|
|
18
18
|
super(container);
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
if (!repulseOptions) {
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
const repulse = container.repulse
|
|
24
|
+
const repulse = container.repulse ?? { particles: [] };
|
|
25
25
|
if (!repulse.finish) {
|
|
26
26
|
if (!repulse.count) {
|
|
27
27
|
repulse.count = 0;
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
}
|
|
34
34
|
if (repulse.clicking) {
|
|
35
35
|
const repulseDistance = container.retina.repulseModeDistance;
|
|
36
|
-
if (!repulseDistance || repulseDistance <
|
|
36
|
+
if (!repulseDistance || repulseDistance < minDistance) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
const repulseRadius = Math.pow(repulseDistance /
|
|
39
|
+
const repulseRadius = Math.pow(repulseDistance / repulseRadiusFactor, repulseRadiusPower), mouseClickPos = container.interactivity.mouse.clickPosition;
|
|
40
40
|
if (mouseClickPos === undefined) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
const range = new engine_1.Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
|
|
44
44
|
for (const particle of query) {
|
|
45
|
-
const { dx, dy, distance } = (0, engine_1.getDistances)(mouseClickPos, particle.position), d = distance **
|
|
45
|
+
const { dx, dy, distance } = (0, engine_1.getDistances)(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
|
|
46
46
|
if (d <= repulseRadius) {
|
|
47
47
|
repulse.particles.push(particle);
|
|
48
48
|
const vect = engine_1.Vector.create(dx, dy);
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
};
|
|
61
61
|
this._hoverRepulse = () => {
|
|
62
62
|
const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
|
|
63
|
-
if (!repulseRadius || repulseRadius <
|
|
63
|
+
if (!repulseRadius || repulseRadius < minRadius || !mousePos) {
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
this._processRepulse(mousePos, repulseRadius, new engine_1.Circle(mousePos.x, mousePos.y, repulseRadius));
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
}
|
|
73
73
|
const { easing, speed, factor, maxSpeed } = repulseOptions, easingFunc = (0, engine_1.getEasing)(easing), velocity = (divRepulse?.speed ?? speed) * factor;
|
|
74
74
|
for (const particle of query) {
|
|
75
|
-
const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position), repulseFactor = (0, engine_1.clamp)(easingFunc(
|
|
75
|
+
const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position), repulseFactor = (0, engine_1.clamp)(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed), normVec = engine_1.Vector.create(!distance ? velocity : (dx / distance) * repulseFactor, !distance ? velocity : (dy / distance) * repulseFactor);
|
|
76
76
|
particle.position.addTo(normVec);
|
|
77
77
|
}
|
|
78
78
|
};
|
|
@@ -87,9 +87,9 @@
|
|
|
87
87
|
}
|
|
88
88
|
query.forEach((item) => {
|
|
89
89
|
const elem = item, pxRatio = container.retina.pixelRatio, pos = {
|
|
90
|
-
x: (elem.offsetLeft + elem.offsetWidth
|
|
91
|
-
y: (elem.offsetTop + elem.offsetHeight
|
|
92
|
-
}, repulseRadius =
|
|
90
|
+
x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
|
|
91
|
+
y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
|
|
92
|
+
}, repulseRadius = elem.offsetWidth * half * pxRatio, area = div.type === "circle"
|
|
93
93
|
? new engine_1.Circle(pos.x, pos.y, repulseRadius)
|
|
94
94
|
: new engine_1.Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), divs = repulse.divs, divRepulse = (0, engine_1.divMode)(divs, elem);
|
|
95
95
|
this._processRepulse(pos, repulseRadius, area, divRepulse);
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
repulse.clicking = false;
|
|
126
|
-
}, repulseOpts.duration *
|
|
126
|
+
}, repulseOpts.duration * engine_1.millisecondsToSeconds);
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
clear() {
|
|
@@ -146,10 +146,11 @@
|
|
|
146
146
|
else {
|
|
147
147
|
(0, engine_1.divModeExecute)(repulseMode, divs, (selector, div) => this._singleSelectorRepulse(selector, div));
|
|
148
148
|
}
|
|
149
|
+
await Promise.resolve();
|
|
149
150
|
}
|
|
150
151
|
isEnabled(particle) {
|
|
151
152
|
const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = (particle?.interactivity ?? options.interactivity).events, divs = events.onDiv, hover = events.onHover, click = events.onClick, divRepulse = (0, engine_1.isDivModeEnabled)(repulseMode, divs);
|
|
152
|
-
if (!(divRepulse || (hover.enable && mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
153
|
+
if (!(divRepulse || (hover.enable && !!mouse.position) || (click.enable && mouse.clickPosition))) {
|
|
153
154
|
return false;
|
|
154
155
|
}
|
|
155
156
|
const hoverMode = hover.mode, clickMode = click.mode;
|