@tsparticles/interaction-external-repulse 4.0.0-beta.15 → 4.0.0-beta.17

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.
@@ -5,6 +5,7 @@ export class RepulseBase {
5
5
  easing;
6
6
  factor;
7
7
  maxSpeed;
8
+ restore;
8
9
  speed;
9
10
  constructor() {
10
11
  this.distance = 200;
@@ -13,6 +14,12 @@ export class RepulseBase {
13
14
  this.speed = 1;
14
15
  this.maxSpeed = 50;
15
16
  this.easing = EasingType.easeOutQuad;
17
+ this.restore = {
18
+ enable: false,
19
+ delay: 0,
20
+ speed: 0.08,
21
+ follow: true,
22
+ };
16
23
  }
17
24
  load(data) {
18
25
  if (isNull(data)) {
@@ -36,5 +43,11 @@ export class RepulseBase {
36
43
  if (data.maxSpeed !== undefined) {
37
44
  this.maxSpeed = data.maxSpeed;
38
45
  }
46
+ if (data.restore !== undefined) {
47
+ this.restore.enable = data.restore.enable ?? this.restore.enable;
48
+ this.restore.delay = data.restore.delay ?? this.restore.delay;
49
+ this.restore.speed = data.restore.speed ?? this.restore.speed;
50
+ this.restore.follow = data.restore.follow ?? this.restore.follow;
51
+ }
39
52
  }
40
53
  }
@@ -1,19 +1,23 @@
1
1
  import { Circle, Rectangle, Vector, clamp, getDistances, half, isInArray, millisecondsToSeconds, safeDocument, } from "@tsparticles/engine";
2
2
  import { DivType, ExternalInteractorBase, divMode, divModeExecute, isDivModeEnabled, mouseMoveEvent, } from "@tsparticles/plugin-interactivity";
3
3
  import { Repulse } from "./Options/Classes/Repulse.js";
4
- const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1;
4
+ const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, minRestoreSpeed = 0.001, maxRestoreSpeed = 1, restoreEpsilon = 0.5;
5
5
  export class Repulser extends ExternalInteractorBase {
6
6
  handleClickMode;
7
7
  _clickVec;
8
+ _interactedThisFrame;
8
9
  _maxDistance;
9
10
  _normVec;
10
11
  _pluginManager;
12
+ _restoreData;
11
13
  constructor(pluginManager, container) {
12
14
  super(container);
13
15
  this._pluginManager = pluginManager;
14
16
  this._maxDistance = 0;
15
17
  this._normVec = Vector.origin;
18
+ this._interactedThisFrame = new Set();
16
19
  this._clickVec = Vector.origin;
20
+ this._restoreData = new Map();
17
21
  container.repulse ??= { particles: [] };
18
22
  this.handleClickMode = (mode, interactivityData) => {
19
23
  const options = this.container.actualOptions, repulseOpts = options.interactivity?.modes.repulse;
@@ -54,6 +58,7 @@ export class Repulser extends ExternalInteractorBase {
54
58
  container.retina.repulseModeDistance = repulse.distance * container.retina.pixelRatio;
55
59
  }
56
60
  interact(interactivityData) {
61
+ this._interactedThisFrame.clear();
57
62
  const container = this.container, options = container.actualOptions, mouseMoveStatus = interactivityData.status === mouseMoveEvent, events = options.interactivity?.events;
58
63
  if (!events) {
59
64
  return;
@@ -70,6 +75,7 @@ export class Repulser extends ExternalInteractorBase {
70
75
  this._singleSelectorRepulse(interactivityData, selector, div);
71
76
  });
72
77
  }
78
+ this._restoreParticles();
73
79
  }
74
80
  isEnabled(interactivityData, particle) {
75
81
  const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
@@ -117,6 +123,7 @@ export class Repulser extends ExternalInteractorBase {
117
123
  for (const particle of query) {
118
124
  const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
119
125
  if (d <= repulseRadius) {
126
+ this._trackInteractedParticle(particle);
120
127
  repulse.particles.push(particle);
121
128
  this._clickVec.x = dx;
122
129
  this._clickVec.y = dy;
@@ -149,9 +156,46 @@ export class Repulser extends ExternalInteractorBase {
149
156
  const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed);
150
157
  this._normVec.x = !distance ? velocity : (dx / distance) * repulseFactor;
151
158
  this._normVec.y = !distance ? velocity : (dy / distance) * repulseFactor;
159
+ this._trackInteractedParticle(particle);
152
160
  particle.position.addTo(this._normVec);
153
161
  }
154
162
  };
163
+ _restoreParticles() {
164
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
165
+ if (!restore?.enable || !this._restoreData.size) {
166
+ return;
167
+ }
168
+ const now = Date.now(), restoreDelay = restore.delay * millisecondsToSeconds, restoreSpeed = Math.max(minRestoreSpeed, Math.min(maxRestoreSpeed, restore.speed));
169
+ for (const [particle, restoreData] of this._restoreData) {
170
+ if (this._interactedThisFrame.has(particle)) {
171
+ continue;
172
+ }
173
+ if (particle.destroyed) {
174
+ this._restoreData.delete(particle);
175
+ continue;
176
+ }
177
+ const target = restoreData.target;
178
+ if (now - restoreData.lastInteractionTime < restoreDelay) {
179
+ continue;
180
+ }
181
+ if (restore.follow && particle.options.move.enable) {
182
+ target.x += particle.velocity.x;
183
+ target.y += particle.velocity.y;
184
+ target.z += particle.velocity.z;
185
+ }
186
+ const dx = target.x - particle.position.x, dy = target.y - particle.position.y, dz = target.z - particle.position.z;
187
+ particle.position.x += dx * restoreSpeed;
188
+ particle.position.y += dy * restoreSpeed;
189
+ particle.position.z += dz * restoreSpeed;
190
+ if (Math.abs(dx) <= restoreEpsilon && Math.abs(dy) <= restoreEpsilon) {
191
+ particle.position.x = target.x;
192
+ particle.position.y = target.y;
193
+ particle.position.z = target.z;
194
+ this._restoreData.delete(particle);
195
+ continue;
196
+ }
197
+ }
198
+ }
155
199
  _singleSelectorRepulse = (interactivityData, selector, div) => {
156
200
  const container = this.container, repulse = container.actualOptions.interactivity?.modes.repulse;
157
201
  if (!repulse) {
@@ -171,4 +215,26 @@ export class Repulser extends ExternalInteractorBase {
171
215
  this._processRepulse(interactivityData, pos, repulseRadius, area, divRepulse);
172
216
  });
173
217
  };
218
+ _trackInteractedParticle(particle) {
219
+ this._interactedThisFrame.add(particle);
220
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
221
+ if (!restore?.enable) {
222
+ return;
223
+ }
224
+ const now = Date.now();
225
+ let restoreData = this._restoreData.get(particle);
226
+ if (!restoreData) {
227
+ restoreData = {
228
+ target: particle.position.copy(),
229
+ lastInteractionTime: now,
230
+ };
231
+ this._restoreData.set(particle, restoreData);
232
+ }
233
+ restoreData.lastInteractionTime = now;
234
+ if (restore.follow && particle.options.move.enable) {
235
+ restoreData.target.x += particle.velocity.x;
236
+ restoreData.target.y += particle.velocity.y;
237
+ restoreData.target.z += particle.velocity.z;
238
+ }
239
+ }
174
240
  }
package/browser/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ensureInteractivityPluginLoaded } from "@tsparticles/plugin-interactivity";
2
2
  import { Repulser } from "./Repulser.js";
3
3
  export async function loadExternalRepulseInteraction(engine) {
4
- engine.checkVersion("4.0.0-beta.15");
4
+ engine.checkVersion("4.0.0-beta.17");
5
5
  await engine.pluginManager.register((e) => {
6
6
  ensureInteractivityPluginLoaded(e);
7
7
  const pluginManager = e.pluginManager;
@@ -1,5 +1,5 @@
1
1
  export async function loadExternalRepulseInteraction(engine) {
2
- engine.checkVersion("4.0.0-beta.15");
2
+ engine.checkVersion("4.0.0-beta.17");
3
3
  await engine.pluginManager.register(async (e) => {
4
4
  const { ensureInteractivityPluginLoaded } = await import("@tsparticles/plugin-interactivity/lazy");
5
5
  ensureInteractivityPluginLoaded(e);
@@ -5,6 +5,7 @@ export class RepulseBase {
5
5
  easing;
6
6
  factor;
7
7
  maxSpeed;
8
+ restore;
8
9
  speed;
9
10
  constructor() {
10
11
  this.distance = 200;
@@ -13,6 +14,12 @@ export class RepulseBase {
13
14
  this.speed = 1;
14
15
  this.maxSpeed = 50;
15
16
  this.easing = EasingType.easeOutQuad;
17
+ this.restore = {
18
+ enable: false,
19
+ delay: 0,
20
+ speed: 0.08,
21
+ follow: true,
22
+ };
16
23
  }
17
24
  load(data) {
18
25
  if (isNull(data)) {
@@ -36,5 +43,11 @@ export class RepulseBase {
36
43
  if (data.maxSpeed !== undefined) {
37
44
  this.maxSpeed = data.maxSpeed;
38
45
  }
46
+ if (data.restore !== undefined) {
47
+ this.restore.enable = data.restore.enable ?? this.restore.enable;
48
+ this.restore.delay = data.restore.delay ?? this.restore.delay;
49
+ this.restore.speed = data.restore.speed ?? this.restore.speed;
50
+ this.restore.follow = data.restore.follow ?? this.restore.follow;
51
+ }
39
52
  }
40
53
  }
package/cjs/Repulser.js CHANGED
@@ -1,19 +1,23 @@
1
1
  import { Circle, Rectangle, Vector, clamp, getDistances, half, isInArray, millisecondsToSeconds, safeDocument, } from "@tsparticles/engine";
2
2
  import { DivType, ExternalInteractorBase, divMode, divModeExecute, isDivModeEnabled, mouseMoveEvent, } from "@tsparticles/plugin-interactivity";
3
3
  import { Repulse } from "./Options/Classes/Repulse.js";
4
- const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1;
4
+ const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, minRestoreSpeed = 0.001, maxRestoreSpeed = 1, restoreEpsilon = 0.5;
5
5
  export class Repulser extends ExternalInteractorBase {
6
6
  handleClickMode;
7
7
  _clickVec;
8
+ _interactedThisFrame;
8
9
  _maxDistance;
9
10
  _normVec;
10
11
  _pluginManager;
12
+ _restoreData;
11
13
  constructor(pluginManager, container) {
12
14
  super(container);
13
15
  this._pluginManager = pluginManager;
14
16
  this._maxDistance = 0;
15
17
  this._normVec = Vector.origin;
18
+ this._interactedThisFrame = new Set();
16
19
  this._clickVec = Vector.origin;
20
+ this._restoreData = new Map();
17
21
  container.repulse ??= { particles: [] };
18
22
  this.handleClickMode = (mode, interactivityData) => {
19
23
  const options = this.container.actualOptions, repulseOpts = options.interactivity?.modes.repulse;
@@ -54,6 +58,7 @@ export class Repulser extends ExternalInteractorBase {
54
58
  container.retina.repulseModeDistance = repulse.distance * container.retina.pixelRatio;
55
59
  }
56
60
  interact(interactivityData) {
61
+ this._interactedThisFrame.clear();
57
62
  const container = this.container, options = container.actualOptions, mouseMoveStatus = interactivityData.status === mouseMoveEvent, events = options.interactivity?.events;
58
63
  if (!events) {
59
64
  return;
@@ -70,6 +75,7 @@ export class Repulser extends ExternalInteractorBase {
70
75
  this._singleSelectorRepulse(interactivityData, selector, div);
71
76
  });
72
77
  }
78
+ this._restoreParticles();
73
79
  }
74
80
  isEnabled(interactivityData, particle) {
75
81
  const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
@@ -117,6 +123,7 @@ export class Repulser extends ExternalInteractorBase {
117
123
  for (const particle of query) {
118
124
  const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
119
125
  if (d <= repulseRadius) {
126
+ this._trackInteractedParticle(particle);
120
127
  repulse.particles.push(particle);
121
128
  this._clickVec.x = dx;
122
129
  this._clickVec.y = dy;
@@ -149,9 +156,46 @@ export class Repulser extends ExternalInteractorBase {
149
156
  const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed);
150
157
  this._normVec.x = !distance ? velocity : (dx / distance) * repulseFactor;
151
158
  this._normVec.y = !distance ? velocity : (dy / distance) * repulseFactor;
159
+ this._trackInteractedParticle(particle);
152
160
  particle.position.addTo(this._normVec);
153
161
  }
154
162
  };
163
+ _restoreParticles() {
164
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
165
+ if (!restore?.enable || !this._restoreData.size) {
166
+ return;
167
+ }
168
+ const now = Date.now(), restoreDelay = restore.delay * millisecondsToSeconds, restoreSpeed = Math.max(minRestoreSpeed, Math.min(maxRestoreSpeed, restore.speed));
169
+ for (const [particle, restoreData] of this._restoreData) {
170
+ if (this._interactedThisFrame.has(particle)) {
171
+ continue;
172
+ }
173
+ if (particle.destroyed) {
174
+ this._restoreData.delete(particle);
175
+ continue;
176
+ }
177
+ const target = restoreData.target;
178
+ if (now - restoreData.lastInteractionTime < restoreDelay) {
179
+ continue;
180
+ }
181
+ if (restore.follow && particle.options.move.enable) {
182
+ target.x += particle.velocity.x;
183
+ target.y += particle.velocity.y;
184
+ target.z += particle.velocity.z;
185
+ }
186
+ const dx = target.x - particle.position.x, dy = target.y - particle.position.y, dz = target.z - particle.position.z;
187
+ particle.position.x += dx * restoreSpeed;
188
+ particle.position.y += dy * restoreSpeed;
189
+ particle.position.z += dz * restoreSpeed;
190
+ if (Math.abs(dx) <= restoreEpsilon && Math.abs(dy) <= restoreEpsilon) {
191
+ particle.position.x = target.x;
192
+ particle.position.y = target.y;
193
+ particle.position.z = target.z;
194
+ this._restoreData.delete(particle);
195
+ continue;
196
+ }
197
+ }
198
+ }
155
199
  _singleSelectorRepulse = (interactivityData, selector, div) => {
156
200
  const container = this.container, repulse = container.actualOptions.interactivity?.modes.repulse;
157
201
  if (!repulse) {
@@ -171,4 +215,26 @@ export class Repulser extends ExternalInteractorBase {
171
215
  this._processRepulse(interactivityData, pos, repulseRadius, area, divRepulse);
172
216
  });
173
217
  };
218
+ _trackInteractedParticle(particle) {
219
+ this._interactedThisFrame.add(particle);
220
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
221
+ if (!restore?.enable) {
222
+ return;
223
+ }
224
+ const now = Date.now();
225
+ let restoreData = this._restoreData.get(particle);
226
+ if (!restoreData) {
227
+ restoreData = {
228
+ target: particle.position.copy(),
229
+ lastInteractionTime: now,
230
+ };
231
+ this._restoreData.set(particle, restoreData);
232
+ }
233
+ restoreData.lastInteractionTime = now;
234
+ if (restore.follow && particle.options.move.enable) {
235
+ restoreData.target.x += particle.velocity.x;
236
+ restoreData.target.y += particle.velocity.y;
237
+ restoreData.target.z += particle.velocity.z;
238
+ }
239
+ }
174
240
  }
package/cjs/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ensureInteractivityPluginLoaded } from "@tsparticles/plugin-interactivity";
2
2
  import { Repulser } from "./Repulser.js";
3
3
  export async function loadExternalRepulseInteraction(engine) {
4
- engine.checkVersion("4.0.0-beta.15");
4
+ engine.checkVersion("4.0.0-beta.17");
5
5
  await engine.pluginManager.register((e) => {
6
6
  ensureInteractivityPluginLoaded(e);
7
7
  const pluginManager = e.pluginManager;
package/cjs/index.lazy.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export async function loadExternalRepulseInteraction(engine) {
2
- engine.checkVersion("4.0.0-beta.15");
2
+ engine.checkVersion("4.0.0-beta.17");
3
3
  await engine.pluginManager.register(async (e) => {
4
4
  const { ensureInteractivityPluginLoaded } = await import("@tsparticles/plugin-interactivity/lazy");
5
5
  ensureInteractivityPluginLoaded(e);
@@ -5,6 +5,7 @@ export class RepulseBase {
5
5
  easing;
6
6
  factor;
7
7
  maxSpeed;
8
+ restore;
8
9
  speed;
9
10
  constructor() {
10
11
  this.distance = 200;
@@ -13,6 +14,12 @@ export class RepulseBase {
13
14
  this.speed = 1;
14
15
  this.maxSpeed = 50;
15
16
  this.easing = EasingType.easeOutQuad;
17
+ this.restore = {
18
+ enable: false,
19
+ delay: 0,
20
+ speed: 0.08,
21
+ follow: true,
22
+ };
16
23
  }
17
24
  load(data) {
18
25
  if (isNull(data)) {
@@ -36,5 +43,11 @@ export class RepulseBase {
36
43
  if (data.maxSpeed !== undefined) {
37
44
  this.maxSpeed = data.maxSpeed;
38
45
  }
46
+ if (data.restore !== undefined) {
47
+ this.restore.enable = data.restore.enable ?? this.restore.enable;
48
+ this.restore.delay = data.restore.delay ?? this.restore.delay;
49
+ this.restore.speed = data.restore.speed ?? this.restore.speed;
50
+ this.restore.follow = data.restore.follow ?? this.restore.follow;
51
+ }
39
52
  }
40
53
  }
package/esm/Repulser.js CHANGED
@@ -1,19 +1,23 @@
1
1
  import { Circle, Rectangle, Vector, clamp, getDistances, half, isInArray, millisecondsToSeconds, safeDocument, } from "@tsparticles/engine";
2
2
  import { DivType, ExternalInteractorBase, divMode, divModeExecute, isDivModeEnabled, mouseMoveEvent, } from "@tsparticles/plugin-interactivity";
3
3
  import { Repulse } from "./Options/Classes/Repulse.js";
4
- const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1;
4
+ const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, minRestoreSpeed = 0.001, maxRestoreSpeed = 1, restoreEpsilon = 0.5;
5
5
  export class Repulser extends ExternalInteractorBase {
6
6
  handleClickMode;
7
7
  _clickVec;
8
+ _interactedThisFrame;
8
9
  _maxDistance;
9
10
  _normVec;
10
11
  _pluginManager;
12
+ _restoreData;
11
13
  constructor(pluginManager, container) {
12
14
  super(container);
13
15
  this._pluginManager = pluginManager;
14
16
  this._maxDistance = 0;
15
17
  this._normVec = Vector.origin;
18
+ this._interactedThisFrame = new Set();
16
19
  this._clickVec = Vector.origin;
20
+ this._restoreData = new Map();
17
21
  container.repulse ??= { particles: [] };
18
22
  this.handleClickMode = (mode, interactivityData) => {
19
23
  const options = this.container.actualOptions, repulseOpts = options.interactivity?.modes.repulse;
@@ -54,6 +58,7 @@ export class Repulser extends ExternalInteractorBase {
54
58
  container.retina.repulseModeDistance = repulse.distance * container.retina.pixelRatio;
55
59
  }
56
60
  interact(interactivityData) {
61
+ this._interactedThisFrame.clear();
57
62
  const container = this.container, options = container.actualOptions, mouseMoveStatus = interactivityData.status === mouseMoveEvent, events = options.interactivity?.events;
58
63
  if (!events) {
59
64
  return;
@@ -70,6 +75,7 @@ export class Repulser extends ExternalInteractorBase {
70
75
  this._singleSelectorRepulse(interactivityData, selector, div);
71
76
  });
72
77
  }
78
+ this._restoreParticles();
73
79
  }
74
80
  isEnabled(interactivityData, particle) {
75
81
  const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
@@ -117,6 +123,7 @@ export class Repulser extends ExternalInteractorBase {
117
123
  for (const particle of query) {
118
124
  const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
119
125
  if (d <= repulseRadius) {
126
+ this._trackInteractedParticle(particle);
120
127
  repulse.particles.push(particle);
121
128
  this._clickVec.x = dx;
122
129
  this._clickVec.y = dy;
@@ -149,9 +156,46 @@ export class Repulser extends ExternalInteractorBase {
149
156
  const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed);
150
157
  this._normVec.x = !distance ? velocity : (dx / distance) * repulseFactor;
151
158
  this._normVec.y = !distance ? velocity : (dy / distance) * repulseFactor;
159
+ this._trackInteractedParticle(particle);
152
160
  particle.position.addTo(this._normVec);
153
161
  }
154
162
  };
163
+ _restoreParticles() {
164
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
165
+ if (!restore?.enable || !this._restoreData.size) {
166
+ return;
167
+ }
168
+ const now = Date.now(), restoreDelay = restore.delay * millisecondsToSeconds, restoreSpeed = Math.max(minRestoreSpeed, Math.min(maxRestoreSpeed, restore.speed));
169
+ for (const [particle, restoreData] of this._restoreData) {
170
+ if (this._interactedThisFrame.has(particle)) {
171
+ continue;
172
+ }
173
+ if (particle.destroyed) {
174
+ this._restoreData.delete(particle);
175
+ continue;
176
+ }
177
+ const target = restoreData.target;
178
+ if (now - restoreData.lastInteractionTime < restoreDelay) {
179
+ continue;
180
+ }
181
+ if (restore.follow && particle.options.move.enable) {
182
+ target.x += particle.velocity.x;
183
+ target.y += particle.velocity.y;
184
+ target.z += particle.velocity.z;
185
+ }
186
+ const dx = target.x - particle.position.x, dy = target.y - particle.position.y, dz = target.z - particle.position.z;
187
+ particle.position.x += dx * restoreSpeed;
188
+ particle.position.y += dy * restoreSpeed;
189
+ particle.position.z += dz * restoreSpeed;
190
+ if (Math.abs(dx) <= restoreEpsilon && Math.abs(dy) <= restoreEpsilon) {
191
+ particle.position.x = target.x;
192
+ particle.position.y = target.y;
193
+ particle.position.z = target.z;
194
+ this._restoreData.delete(particle);
195
+ continue;
196
+ }
197
+ }
198
+ }
155
199
  _singleSelectorRepulse = (interactivityData, selector, div) => {
156
200
  const container = this.container, repulse = container.actualOptions.interactivity?.modes.repulse;
157
201
  if (!repulse) {
@@ -171,4 +215,26 @@ export class Repulser extends ExternalInteractorBase {
171
215
  this._processRepulse(interactivityData, pos, repulseRadius, area, divRepulse);
172
216
  });
173
217
  };
218
+ _trackInteractedParticle(particle) {
219
+ this._interactedThisFrame.add(particle);
220
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
221
+ if (!restore?.enable) {
222
+ return;
223
+ }
224
+ const now = Date.now();
225
+ let restoreData = this._restoreData.get(particle);
226
+ if (!restoreData) {
227
+ restoreData = {
228
+ target: particle.position.copy(),
229
+ lastInteractionTime: now,
230
+ };
231
+ this._restoreData.set(particle, restoreData);
232
+ }
233
+ restoreData.lastInteractionTime = now;
234
+ if (restore.follow && particle.options.move.enable) {
235
+ restoreData.target.x += particle.velocity.x;
236
+ restoreData.target.y += particle.velocity.y;
237
+ restoreData.target.z += particle.velocity.z;
238
+ }
239
+ }
174
240
  }
package/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ensureInteractivityPluginLoaded } from "@tsparticles/plugin-interactivity";
2
2
  import { Repulser } from "./Repulser.js";
3
3
  export async function loadExternalRepulseInteraction(engine) {
4
- engine.checkVersion("4.0.0-beta.15");
4
+ engine.checkVersion("4.0.0-beta.17");
5
5
  await engine.pluginManager.register((e) => {
6
6
  ensureInteractivityPluginLoaded(e);
7
7
  const pluginManager = e.pluginManager;
package/esm/index.lazy.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export async function loadExternalRepulseInteraction(engine) {
2
- engine.checkVersion("4.0.0-beta.15");
2
+ engine.checkVersion("4.0.0-beta.17");
3
3
  await engine.pluginManager.register(async (e) => {
4
4
  const { ensureInteractivityPluginLoaded } = await import("@tsparticles/plugin-interactivity/lazy");
5
5
  ensureInteractivityPluginLoaded(e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsparticles/interaction-external-repulse",
3
- "version": "4.0.0-beta.15",
3
+ "version": "4.0.0-beta.17",
4
4
  "description": "tsParticles repulse external interaction",
5
5
  "homepage": "https://particles.js.org",
6
6
  "repository": {
@@ -101,7 +101,7 @@
101
101
  },
102
102
  "type": "module",
103
103
  "peerDependencies": {
104
- "@tsparticles/engine": "4.0.0-beta.15",
105
- "@tsparticles/plugin-interactivity": "4.0.0-beta.15"
104
+ "@tsparticles/engine": "4.0.0-beta.17",
105
+ "@tsparticles/plugin-interactivity": "4.0.0-beta.17"
106
106
  }
107
107
  }
package/report.html CHANGED
@@ -4930,7 +4930,7 @@ var drawChart = (function (exports) {
4930
4930
  </script>
4931
4931
  <script>
4932
4932
  /*<!--*/
4933
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"tsparticles.interaction.external.repulse.js","children":[{"name":"dist/browser","children":[{"name":"Options/Classes","children":[{"uid":"e0c98763-1","name":"RepulseBase.js"},{"uid":"e0c98763-3","name":"RepulseDiv.js"},{"uid":"e0c98763-5","name":"Repulse.js"}]},{"uid":"e0c98763-7","name":"Repulser.js"},{"uid":"e0c98763-9","name":"index.js"},{"uid":"e0c98763-11","name":"browser.js"}]}]}],"isRoot":true},"nodeParts":{"e0c98763-1":{"renderedLength":1113,"gzipLength":0,"brotliLength":0,"metaUid":"e0c98763-0"},"e0c98763-3":{"renderedLength":404,"gzipLength":0,"brotliLength":0,"metaUid":"e0c98763-2"},"e0c98763-5":{"renderedLength":395,"gzipLength":0,"brotliLength":0,"metaUid":"e0c98763-4"},"e0c98763-7":{"renderedLength":9220,"gzipLength":0,"brotliLength":0,"metaUid":"e0c98763-6"},"e0c98763-9":{"renderedLength":467,"gzipLength":0,"brotliLength":0,"metaUid":"e0c98763-8"},"e0c98763-11":{"renderedLength":203,"gzipLength":0,"brotliLength":0,"metaUid":"e0c98763-10"}},"nodeMetas":{"e0c98763-0":{"id":"/dist/browser/Options/Classes/RepulseBase.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"e0c98763-1"},"imported":[{"uid":"e0c98763-13"}],"importedBy":[{"uid":"e0c98763-8"},{"uid":"e0c98763-2"},{"uid":"e0c98763-4"}]},"e0c98763-2":{"id":"/dist/browser/Options/Classes/RepulseDiv.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"e0c98763-3"},"imported":[{"uid":"e0c98763-13"},{"uid":"e0c98763-0"}],"importedBy":[{"uid":"e0c98763-8"},{"uid":"e0c98763-4"}]},"e0c98763-4":{"id":"/dist/browser/Options/Classes/Repulse.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"e0c98763-5"},"imported":[{"uid":"e0c98763-13"},{"uid":"e0c98763-0"},{"uid":"e0c98763-2"}],"importedBy":[{"uid":"e0c98763-8"},{"uid":"e0c98763-6"}]},"e0c98763-6":{"id":"/dist/browser/Repulser.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"e0c98763-7"},"imported":[{"uid":"e0c98763-13"},{"uid":"e0c98763-12"},{"uid":"e0c98763-4"}],"importedBy":[{"uid":"e0c98763-8"}]},"e0c98763-8":{"id":"/dist/browser/index.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"e0c98763-9"},"imported":[{"uid":"e0c98763-12"},{"uid":"e0c98763-6"},{"uid":"e0c98763-0"},{"uid":"e0c98763-2"},{"uid":"e0c98763-4"}],"importedBy":[{"uid":"e0c98763-10"}]},"e0c98763-10":{"id":"/dist/browser/browser.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"e0c98763-11"},"imported":[{"uid":"e0c98763-8"}],"importedBy":[],"isEntry":true},"e0c98763-12":{"id":"@tsparticles/plugin-interactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"e0c98763-8"},{"uid":"e0c98763-6"}],"isExternal":true},"e0c98763-13":{"id":"@tsparticles/engine","moduleParts":{},"imported":[],"importedBy":[{"uid":"e0c98763-6"},{"uid":"e0c98763-0"},{"uid":"e0c98763-2"},{"uid":"e0c98763-4"}],"isExternal":true}},"env":{"rollup":"4.60.3"},"options":{"gzip":false,"brotli":false,"sourcemap":false}};
4933
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"tsparticles.interaction.external.repulse.js","children":[{"name":"dist/browser","children":[{"name":"Options/Classes","children":[{"uid":"80646799-1","name":"RepulseBase.js"},{"uid":"80646799-3","name":"RepulseDiv.js"},{"uid":"80646799-5","name":"Repulse.js"}]},{"uid":"80646799-7","name":"Repulser.js"},{"uid":"80646799-9","name":"index.js"},{"uid":"80646799-11","name":"browser.js"}]}]}],"isRoot":true},"nodeParts":{"80646799-1":{"renderedLength":1672,"gzipLength":0,"brotliLength":0,"metaUid":"80646799-0"},"80646799-3":{"renderedLength":404,"gzipLength":0,"brotliLength":0,"metaUid":"80646799-2"},"80646799-5":{"renderedLength":395,"gzipLength":0,"brotliLength":0,"metaUid":"80646799-4"},"80646799-7":{"renderedLength":12428,"gzipLength":0,"brotliLength":0,"metaUid":"80646799-6"},"80646799-9":{"renderedLength":467,"gzipLength":0,"brotliLength":0,"metaUid":"80646799-8"},"80646799-11":{"renderedLength":203,"gzipLength":0,"brotliLength":0,"metaUid":"80646799-10"}},"nodeMetas":{"80646799-0":{"id":"/dist/browser/Options/Classes/RepulseBase.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"80646799-1"},"imported":[{"uid":"80646799-13"}],"importedBy":[{"uid":"80646799-8"},{"uid":"80646799-2"},{"uid":"80646799-4"}]},"80646799-2":{"id":"/dist/browser/Options/Classes/RepulseDiv.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"80646799-3"},"imported":[{"uid":"80646799-13"},{"uid":"80646799-0"}],"importedBy":[{"uid":"80646799-8"},{"uid":"80646799-4"}]},"80646799-4":{"id":"/dist/browser/Options/Classes/Repulse.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"80646799-5"},"imported":[{"uid":"80646799-13"},{"uid":"80646799-0"},{"uid":"80646799-2"}],"importedBy":[{"uid":"80646799-8"},{"uid":"80646799-6"}]},"80646799-6":{"id":"/dist/browser/Repulser.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"80646799-7"},"imported":[{"uid":"80646799-13"},{"uid":"80646799-12"},{"uid":"80646799-4"}],"importedBy":[{"uid":"80646799-8"}]},"80646799-8":{"id":"/dist/browser/index.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"80646799-9"},"imported":[{"uid":"80646799-12"},{"uid":"80646799-6"},{"uid":"80646799-0"},{"uid":"80646799-2"},{"uid":"80646799-4"}],"importedBy":[{"uid":"80646799-10"}]},"80646799-10":{"id":"/dist/browser/browser.js","moduleParts":{"tsparticles.interaction.external.repulse.js":"80646799-11"},"imported":[{"uid":"80646799-8"}],"importedBy":[],"isEntry":true},"80646799-12":{"id":"@tsparticles/plugin-interactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"80646799-8"},{"uid":"80646799-6"}],"isExternal":true},"80646799-13":{"id":"@tsparticles/engine","moduleParts":{},"imported":[],"importedBy":[{"uid":"80646799-6"},{"uid":"80646799-0"},{"uid":"80646799-2"},{"uid":"80646799-4"}],"isExternal":true}},"env":{"rollup":"4.60.3"},"options":{"gzip":false,"brotli":false,"sourcemap":false}};
4934
4934
 
4935
4935
  const run = () => {
4936
4936
  const width = window.innerWidth;
@@ -1,5 +1,5 @@
1
1
  (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* External Interaction v4.0.0-beta.15 */
2
+ /* External Interaction v4.0.0-beta.17 */
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tsparticles/plugin-interactivity'), require('@tsparticles/engine')) :
5
5
  typeof define === 'function' && define.amd ? define(['exports', '@tsparticles/plugin-interactivity', '@tsparticles/engine'], factory) :
@@ -12,6 +12,7 @@
12
12
  easing;
13
13
  factor;
14
14
  maxSpeed;
15
+ restore;
15
16
  speed;
16
17
  constructor() {
17
18
  this.distance = 200;
@@ -20,6 +21,12 @@
20
21
  this.speed = 1;
21
22
  this.maxSpeed = 50;
22
23
  this.easing = engine.EasingType.easeOutQuad;
24
+ this.restore = {
25
+ enable: false,
26
+ delay: 0,
27
+ speed: 0.08,
28
+ follow: true,
29
+ };
23
30
  }
24
31
  load(data) {
25
32
  if (engine.isNull(data)) {
@@ -43,6 +50,12 @@
43
50
  if (data.maxSpeed !== undefined) {
44
51
  this.maxSpeed = data.maxSpeed;
45
52
  }
53
+ if (data.restore !== undefined) {
54
+ this.restore.enable = data.restore.enable ?? this.restore.enable;
55
+ this.restore.delay = data.restore.delay ?? this.restore.delay;
56
+ this.restore.speed = data.restore.speed ?? this.restore.speed;
57
+ this.restore.follow = data.restore.follow ?? this.restore.follow;
58
+ }
46
59
  }
47
60
  }
48
61
 
@@ -78,19 +91,23 @@
78
91
  }
79
92
  }
80
93
 
81
- const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1;
94
+ const repulseMode = "repulse", minDistance = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius = 0, minSpeed = 0, easingOffset = 1, minRestoreSpeed = 0.001, maxRestoreSpeed = 1, restoreEpsilon = 0.5;
82
95
  class Repulser extends pluginInteractivity.ExternalInteractorBase {
83
96
  handleClickMode;
84
97
  _clickVec;
98
+ _interactedThisFrame;
85
99
  _maxDistance;
86
100
  _normVec;
87
101
  _pluginManager;
102
+ _restoreData;
88
103
  constructor(pluginManager, container) {
89
104
  super(container);
90
105
  this._pluginManager = pluginManager;
91
106
  this._maxDistance = 0;
92
107
  this._normVec = engine.Vector.origin;
108
+ this._interactedThisFrame = new Set();
93
109
  this._clickVec = engine.Vector.origin;
110
+ this._restoreData = new Map();
94
111
  container.repulse ??= { particles: [] };
95
112
  this.handleClickMode = (mode, interactivityData) => {
96
113
  const options = this.container.actualOptions, repulseOpts = options.interactivity?.modes.repulse;
@@ -131,6 +148,7 @@
131
148
  container.retina.repulseModeDistance = repulse.distance * container.retina.pixelRatio;
132
149
  }
133
150
  interact(interactivityData) {
151
+ this._interactedThisFrame.clear();
134
152
  const container = this.container, options = container.actualOptions, mouseMoveStatus = interactivityData.status === pluginInteractivity.mouseMoveEvent, events = options.interactivity?.events;
135
153
  if (!events) {
136
154
  return;
@@ -147,6 +165,7 @@
147
165
  this._singleSelectorRepulse(interactivityData, selector, div);
148
166
  });
149
167
  }
168
+ this._restoreParticles();
150
169
  }
151
170
  isEnabled(interactivityData, particle) {
152
171
  const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
@@ -194,6 +213,7 @@
194
213
  for (const particle of query) {
195
214
  const { dx, dy, distance } = engine.getDistances(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
196
215
  if (d <= repulseRadius) {
216
+ this._trackInteractedParticle(particle);
197
217
  repulse.particles.push(particle);
198
218
  this._clickVec.x = dx;
199
219
  this._clickVec.y = dy;
@@ -226,9 +246,46 @@
226
246
  const { dx, dy, distance } = engine.getDistances(particle.position, position), repulseFactor = engine.clamp(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed);
227
247
  this._normVec.x = !distance ? velocity : (dx / distance) * repulseFactor;
228
248
  this._normVec.y = !distance ? velocity : (dy / distance) * repulseFactor;
249
+ this._trackInteractedParticle(particle);
229
250
  particle.position.addTo(this._normVec);
230
251
  }
231
252
  };
253
+ _restoreParticles() {
254
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
255
+ if (!restore?.enable || !this._restoreData.size) {
256
+ return;
257
+ }
258
+ const now = Date.now(), restoreDelay = restore.delay * engine.millisecondsToSeconds, restoreSpeed = Math.max(minRestoreSpeed, Math.min(maxRestoreSpeed, restore.speed));
259
+ for (const [particle, restoreData] of this._restoreData) {
260
+ if (this._interactedThisFrame.has(particle)) {
261
+ continue;
262
+ }
263
+ if (particle.destroyed) {
264
+ this._restoreData.delete(particle);
265
+ continue;
266
+ }
267
+ const target = restoreData.target;
268
+ if (now - restoreData.lastInteractionTime < restoreDelay) {
269
+ continue;
270
+ }
271
+ if (restore.follow && particle.options.move.enable) {
272
+ target.x += particle.velocity.x;
273
+ target.y += particle.velocity.y;
274
+ target.z += particle.velocity.z;
275
+ }
276
+ const dx = target.x - particle.position.x, dy = target.y - particle.position.y, dz = target.z - particle.position.z;
277
+ particle.position.x += dx * restoreSpeed;
278
+ particle.position.y += dy * restoreSpeed;
279
+ particle.position.z += dz * restoreSpeed;
280
+ if (Math.abs(dx) <= restoreEpsilon && Math.abs(dy) <= restoreEpsilon) {
281
+ particle.position.x = target.x;
282
+ particle.position.y = target.y;
283
+ particle.position.z = target.z;
284
+ this._restoreData.delete(particle);
285
+ continue;
286
+ }
287
+ }
288
+ }
232
289
  _singleSelectorRepulse = (interactivityData, selector, div) => {
233
290
  const container = this.container, repulse = container.actualOptions.interactivity?.modes.repulse;
234
291
  if (!repulse) {
@@ -248,10 +305,32 @@
248
305
  this._processRepulse(interactivityData, pos, repulseRadius, area, divRepulse);
249
306
  });
250
307
  };
308
+ _trackInteractedParticle(particle) {
309
+ this._interactedThisFrame.add(particle);
310
+ const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
311
+ if (!restore?.enable) {
312
+ return;
313
+ }
314
+ const now = Date.now();
315
+ let restoreData = this._restoreData.get(particle);
316
+ if (!restoreData) {
317
+ restoreData = {
318
+ target: particle.position.copy(),
319
+ lastInteractionTime: now,
320
+ };
321
+ this._restoreData.set(particle, restoreData);
322
+ }
323
+ restoreData.lastInteractionTime = now;
324
+ if (restore.follow && particle.options.move.enable) {
325
+ restoreData.target.x += particle.velocity.x;
326
+ restoreData.target.y += particle.velocity.y;
327
+ restoreData.target.z += particle.velocity.z;
328
+ }
329
+ }
251
330
  }
252
331
 
253
332
  async function loadExternalRepulseInteraction(engine) {
254
- engine.checkVersion("4.0.0-beta.15");
333
+ engine.checkVersion("4.0.0-beta.17");
255
334
  await engine.pluginManager.register((e) => {
256
335
  pluginInteractivity.ensureInteractivityPluginLoaded(e);
257
336
  const pluginManager = e.pluginManager;
@@ -1 +1 @@
1
- !function(t){t.__tsParticlesInternals=t.__tsParticlesInternals||{},t.__tsParticlesInternals.bundles=t.__tsParticlesInternals.bundles||{},t.__tsParticlesInternals.effects=t.__tsParticlesInternals.effects||{},t.__tsParticlesInternals.engine=t.__tsParticlesInternals.engine||{},t.__tsParticlesInternals.interactions=t.__tsParticlesInternals.interactions||{},t.__tsParticlesInternals.palettes=t.__tsParticlesInternals.palettes||{},t.__tsParticlesInternals.paths=t.__tsParticlesInternals.paths||{},t.__tsParticlesInternals.plugins=t.__tsParticlesInternals.plugins||{},t.__tsParticlesInternals.plugins=t.__tsParticlesInternals.plugins||{},t.__tsParticlesInternals.plugins.emittersShapes=t.__tsParticlesInternals.plugins.emittersShapes||{},t.__tsParticlesInternals.presets=t.__tsParticlesInternals.presets||{},t.__tsParticlesInternals.shapes=t.__tsParticlesInternals.shapes||{},t.__tsParticlesInternals.updaters=t.__tsParticlesInternals.updaters||{},t.__tsParticlesInternals.utils=t.__tsParticlesInternals.utils||{},t.__tsParticlesInternals.canvas=t.__tsParticlesInternals.canvas||{},t.__tsParticlesInternals.canvas=t.__tsParticlesInternals.canvas||{},t.__tsParticlesInternals.canvas.utils=t.__tsParticlesInternals.canvas.utils||{},t.__tsParticlesInternals.path=t.__tsParticlesInternals.path||{},t.__tsParticlesInternals.path=t.__tsParticlesInternals.path||{},t.__tsParticlesInternals.path.utils=t.__tsParticlesInternals.path.utils||{};var e="undefined"!=typeof Proxy?function(t){return new Proxy(t,{get:function(t,e){return e in t||(t[e]={}),t[e]}})}:function(t){return t};t.__tsParticlesInternals.bundles=e(t.__tsParticlesInternals.bundles),t.__tsParticlesInternals.effects=e(t.__tsParticlesInternals.effects),t.__tsParticlesInternals.interactions=e(t.__tsParticlesInternals.interactions),t.__tsParticlesInternals.palettes=e(t.__tsParticlesInternals.palettes),t.__tsParticlesInternals.paths=e(t.__tsParticlesInternals.paths),t.__tsParticlesInternals.plugins=e(t.__tsParticlesInternals.plugins),t.__tsParticlesInternals.plugins.emittersShapes=e(t.__tsParticlesInternals.plugins.emittersShapes),t.__tsParticlesInternals.presets=e(t.__tsParticlesInternals.presets),t.__tsParticlesInternals.shapes=e(t.__tsParticlesInternals.shapes),t.__tsParticlesInternals.updaters=e(t.__tsParticlesInternals.updaters),t.__tsParticlesInternals.utils=e(t.__tsParticlesInternals.utils),t.__tsParticlesInternals.canvas=e(t.__tsParticlesInternals.canvas),t.__tsParticlesInternals.path=e(t.__tsParticlesInternals.path),t.tsparticlesInternalExports=t.tsparticlesInternalExports||{}}("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:this),function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("@tsparticles/plugin-interactivity"),require("@tsparticles/engine")):"function"==typeof define&&define.amd?define(["exports","@tsparticles/plugin-interactivity","@tsparticles/engine"],e):e(((t="undefined"!=typeof globalThis?globalThis:t||self).__tsParticlesInternals=t.__tsParticlesInternals||{},t.__tsParticlesInternals.interactions=t.__tsParticlesInternals.interactions||{},t.__tsParticlesInternals.interactions.externalRepulse=t.__tsParticlesInternals.interactions.externalRepulse||{}),t.__tsParticlesInternals.plugins.interactivity,t.__tsParticlesInternals.engine)}(this,function(t,e,s){"use strict";class n{distance;duration;easing;factor;maxSpeed;speed;constructor(){this.distance=200,this.duration=.4,this.factor=100,this.speed=1,this.maxSpeed=50,this.easing=s.EasingType.easeOutQuad}load(t){s.isNull(t)||(void 0!==t.distance&&(this.distance=t.distance),void 0!==t.duration&&(this.duration=t.duration),void 0!==t.easing&&(this.easing=t.easing),void 0!==t.factor&&(this.factor=t.factor),void 0!==t.speed&&(this.speed=t.speed),void 0!==t.maxSpeed&&(this.maxSpeed=t.maxSpeed))}}class i extends n{selectors;constructor(){super(),this.selectors=[]}load(t){super.load(t),s.isNull(t)||void 0!==t.selectors&&(this.selectors=t.selectors)}}class a extends n{divs;load(t){super.load(t),s.isNull(t)||(this.divs=s.executeOnSingleOrMultiple(t.divs,t=>{const e=new i;return e.load(t),e}))}}const r="repulse";class l extends e.ExternalInteractorBase{handleClickMode;_clickVec;_maxDistance;_normVec;_pluginManager;constructor(t,e){super(e),this._pluginManager=t,this._maxDistance=0,this._normVec=s.Vector.origin,this._clickVec=s.Vector.origin,e.repulse??={particles:[]},this.handleClickMode=(t,n)=>{const i=this.container.actualOptions,a=i.interactivity?.modes.repulse;if(!a||t!==r)return;e.repulse??={particles:[]};const l=e.repulse;l.clicking=!0,l.count=0;for(const t of e.repulse.particles)this.isEnabled(n,t)&&t.velocity.setTo(t.initialVelocity);l.particles=[],l.finish=!1,setTimeout(()=>{e.destroyed||(l.clicking=!1)},a.duration*s.millisecondsToSeconds)}}get maxDistance(){return this._maxDistance}clear(){}init(){const t=this.container,e=t.actualOptions.interactivity?.modes.repulse;e&&(this._maxDistance=e.distance,t.retina.repulseModeDistance=e.distance*t.retina.pixelRatio)}interact(t){const n=this.container.actualOptions,i=t.status===e.mouseMoveEvent,a=n.interactivity?.events;if(!a)return;const l=a.onHover,c=l.enable,o=l.mode,_=a.onClick,p=_.enable,u=_.mode,d=a.onDiv;i&&c&&s.isInArray(r,o)?this._hoverRepulse(t):p&&s.isInArray(r,u)?this._clickRepulse(t):e.divModeExecute(r,d,(e,s)=>{this._singleSelectorRepulse(t,e,s)})}isEnabled(t,n){const i=this.container.actualOptions,a=t.mouse,l=(n?.interactivity??i.interactivity)?.events;if(!l)return!1;const c=l.onDiv,o=l.onHover,_=l.onClick,p=e.isDivModeEnabled(r,c);if(!(p||o.enable&&a.position||_.enable&&a.clickPosition))return!1;const u=o.mode,d=_.mode;return s.isInArray(r,u)||s.isInArray(r,d)||p}loadModeOptions(t,...e){t.repulse??=new a;for(const s of e)t.repulse.load(s?.repulse)}reset(){}_clickRepulse=t=>{const e=this.container,n=e.actualOptions.interactivity?.modes.repulse;if(!n)return;const i=e.repulse??{particles:[]};if(i.finish||(i.count??=0,i.count++,i.count===e.particles.count&&(i.finish=!0)),i.clicking){const a=e.retina.repulseModeDistance;if(!a||a<0)return;const r=Math.pow(a/6,3),l=t.mouse.clickPosition;if(void 0===l)return;const c=new s.Circle(l.x,l.y,r),o=e.particles.grid.query(c,e=>this.isEnabled(t,e));for(const t of o){const{dx:e,dy:a,distance:c}=s.getDistances(l,t.position),o=c**2,_=-r*n.speed/o;o<=r&&(i.particles.push(t),this._clickVec.x=e,this._clickVec.y=a,this._clickVec.length=_,t.velocity.setTo(this._clickVec))}}else if(!1===i.clicking){for(const t of i.particles)t.velocity.setTo(t.initialVelocity);i.particles=[]}};_hoverRepulse=t=>{const e=this.container,n=t.mouse.position,i=e.retina.repulseModeDistance;!i||i<0||!n||this._processRepulse(t,n,i,new s.Circle(n.x,n.y,i))};_processRepulse=(t,e,n,i,a)=>{const r=this.container,l=r.particles.grid.query(i,e=>this.isEnabled(t,e)),c=r.actualOptions.interactivity?.modes.repulse;if(!c)return;const{easing:o,speed:_,factor:p,maxSpeed:u}=c,d=this._pluginManager.getEasing(o),h=(a?.speed??_)*p;for(const t of l){const{dx:i,dy:a,distance:r}=s.getDistances(t.position,e),l=s.clamp(d(1-r/n)*h,0,u);this._normVec.x=r?i/r*l:h,this._normVec.y=r?a/r*l:h,t.position.addTo(this._normVec)}};_singleSelectorRepulse=(t,n,i)=>{const a=this.container,r=a.actualOptions.interactivity?.modes.repulse;if(!r)return;const l=s.safeDocument().querySelectorAll(n);l.length&&l.forEach(n=>{const l=n,c=a.retina.pixelRatio,o={x:(l.offsetLeft+l.offsetWidth*s.half)*c,y:(l.offsetTop+l.offsetHeight*s.half)*c},_=l.offsetWidth*s.half*c,p=i.type===e.DivType.circle?new s.Circle(o.x,o.y,_):new s.Rectangle(l.offsetLeft*c,l.offsetTop*c,l.offsetWidth*c,l.offsetHeight*c),u=r.divs,d=e.divMode(u,l);this._processRepulse(t,o,_,p,d)})}}async function c(t){t.checkVersion("4.0.0-beta.15"),await t.pluginManager.register(t=>{e.ensureInteractivityPluginLoaded(t);const s=t.pluginManager;s.addInteractor?.("externalRepulse",t=>Promise.resolve(new l(s,t)))})}const o=globalThis;o.__tsParticlesInternals=o.__tsParticlesInternals??{},o.loadExternalRepulseInteraction=c,t.Repulse=a,t.RepulseBase=n,t.RepulseDiv=i,t.loadExternalRepulseInteraction=c}),Object.assign(globalThis.window||globalThis,{loadExternalRepulseInteraction:(globalThis.__tsParticlesInternals.interactions.externalRepulse||{}).loadExternalRepulseInteraction}),delete(globalThis.window||globalThis).tsparticlesInternalExports;
1
+ !function(e){e.__tsParticlesInternals=e.__tsParticlesInternals||{},e.__tsParticlesInternals.bundles=e.__tsParticlesInternals.bundles||{},e.__tsParticlesInternals.effects=e.__tsParticlesInternals.effects||{},e.__tsParticlesInternals.engine=e.__tsParticlesInternals.engine||{},e.__tsParticlesInternals.interactions=e.__tsParticlesInternals.interactions||{},e.__tsParticlesInternals.palettes=e.__tsParticlesInternals.palettes||{},e.__tsParticlesInternals.paths=e.__tsParticlesInternals.paths||{},e.__tsParticlesInternals.plugins=e.__tsParticlesInternals.plugins||{},e.__tsParticlesInternals.plugins=e.__tsParticlesInternals.plugins||{},e.__tsParticlesInternals.plugins.emittersShapes=e.__tsParticlesInternals.plugins.emittersShapes||{},e.__tsParticlesInternals.presets=e.__tsParticlesInternals.presets||{},e.__tsParticlesInternals.shapes=e.__tsParticlesInternals.shapes||{},e.__tsParticlesInternals.updaters=e.__tsParticlesInternals.updaters||{},e.__tsParticlesInternals.utils=e.__tsParticlesInternals.utils||{},e.__tsParticlesInternals.canvas=e.__tsParticlesInternals.canvas||{},e.__tsParticlesInternals.canvas=e.__tsParticlesInternals.canvas||{},e.__tsParticlesInternals.canvas.utils=e.__tsParticlesInternals.canvas.utils||{},e.__tsParticlesInternals.path=e.__tsParticlesInternals.path||{},e.__tsParticlesInternals.path=e.__tsParticlesInternals.path||{},e.__tsParticlesInternals.path.utils=e.__tsParticlesInternals.path.utils||{};var t="undefined"!=typeof Proxy?function(e){return new Proxy(e,{get:function(e,t){return t in e||(e[t]={}),e[t]}})}:function(e){return e};e.__tsParticlesInternals.bundles=t(e.__tsParticlesInternals.bundles),e.__tsParticlesInternals.effects=t(e.__tsParticlesInternals.effects),e.__tsParticlesInternals.interactions=t(e.__tsParticlesInternals.interactions),e.__tsParticlesInternals.palettes=t(e.__tsParticlesInternals.palettes),e.__tsParticlesInternals.paths=t(e.__tsParticlesInternals.paths),e.__tsParticlesInternals.plugins=t(e.__tsParticlesInternals.plugins),e.__tsParticlesInternals.plugins.emittersShapes=t(e.__tsParticlesInternals.plugins.emittersShapes),e.__tsParticlesInternals.presets=t(e.__tsParticlesInternals.presets),e.__tsParticlesInternals.shapes=t(e.__tsParticlesInternals.shapes),e.__tsParticlesInternals.updaters=t(e.__tsParticlesInternals.updaters),e.__tsParticlesInternals.utils=t(e.__tsParticlesInternals.utils),e.__tsParticlesInternals.canvas=t(e.__tsParticlesInternals.canvas),e.__tsParticlesInternals.path=t(e.__tsParticlesInternals.path),e.tsparticlesInternalExports=e.tsparticlesInternalExports||{}}("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:this),function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@tsparticles/plugin-interactivity"),require("@tsparticles/engine")):"function"==typeof define&&define.amd?define(["exports","@tsparticles/plugin-interactivity","@tsparticles/engine"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).__tsParticlesInternals=e.__tsParticlesInternals||{},e.__tsParticlesInternals.interactions=e.__tsParticlesInternals.interactions||{},e.__tsParticlesInternals.interactions.externalRepulse=e.__tsParticlesInternals.interactions.externalRepulse||{}),e.__tsParticlesInternals.plugins.interactivity,e.__tsParticlesInternals.engine)}(this,function(e,t,s){"use strict";class i{distance;duration;easing;factor;maxSpeed;restore;speed;constructor(){this.distance=200,this.duration=.4,this.factor=100,this.speed=1,this.maxSpeed=50,this.easing=s.EasingType.easeOutQuad,this.restore={enable:!1,delay:0,speed:.08,follow:!0}}load(e){s.isNull(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),void 0!==e.restore&&(this.restore.enable=e.restore.enable??this.restore.enable,this.restore.delay=e.restore.delay??this.restore.delay,this.restore.speed=e.restore.speed??this.restore.speed,this.restore.follow=e.restore.follow??this.restore.follow))}}class n extends i{selectors;constructor(){super(),this.selectors=[]}load(e){super.load(e),s.isNull(e)||void 0!==e.selectors&&(this.selectors=e.selectors)}}class a extends i{divs;load(e){super.load(e),s.isNull(e)||(this.divs=s.executeOnSingleOrMultiple(e.divs,e=>{const t=new n;return t.load(e),t}))}}const r="repulse";class l extends t.ExternalInteractorBase{handleClickMode;_clickVec;_interactedThisFrame;_maxDistance;_normVec;_pluginManager;_restoreData;constructor(e,t){super(t),this._pluginManager=e,this._maxDistance=0,this._normVec=s.Vector.origin,this._interactedThisFrame=new Set,this._clickVec=s.Vector.origin,this._restoreData=new Map,t.repulse??={particles:[]},this.handleClickMode=(e,i)=>{const n=this.container.actualOptions,a=n.interactivity?.modes.repulse;if(!a||e!==r)return;t.repulse??={particles:[]};const l=t.repulse;l.clicking=!0,l.count=0;for(const e of t.repulse.particles)this.isEnabled(i,e)&&e.velocity.setTo(e.initialVelocity);l.particles=[],l.finish=!1,setTimeout(()=>{t.destroyed||(l.clicking=!1)},a.duration*s.millisecondsToSeconds)}}get maxDistance(){return this._maxDistance}clear(){}init(){const e=this.container,t=e.actualOptions.interactivity?.modes.repulse;t&&(this._maxDistance=t.distance,e.retina.repulseModeDistance=t.distance*e.retina.pixelRatio)}interact(e){this._interactedThisFrame.clear();const i=this.container.actualOptions,n=e.status===t.mouseMoveEvent,a=i.interactivity?.events;if(!a)return;const l=a.onHover,c=l.enable,o=l.mode,_=a.onClick,p=_.enable,d=_.mode,u=a.onDiv;n&&c&&s.isInArray(r,o)?this._hoverRepulse(e):p&&s.isInArray(r,d)?this._clickRepulse(e):t.divModeExecute(r,u,(t,s)=>{this._singleSelectorRepulse(e,t,s)}),this._restoreParticles()}isEnabled(e,i){const n=this.container.actualOptions,a=e.mouse,l=(i?.interactivity??n.interactivity)?.events;if(!l)return!1;const c=l.onDiv,o=l.onHover,_=l.onClick,p=t.isDivModeEnabled(r,c);if(!(p||o.enable&&a.position||_.enable&&a.clickPosition))return!1;const d=o.mode,u=_.mode;return s.isInArray(r,d)||s.isInArray(r,u)||p}loadModeOptions(e,...t){e.repulse??=new a;for(const s of t)e.repulse.load(s?.repulse)}reset(){}_clickRepulse=e=>{const t=this.container,i=t.actualOptions.interactivity?.modes.repulse;if(!i)return;const n=t.repulse??{particles:[]};if(n.finish||(n.count??=0,n.count++,n.count===t.particles.count&&(n.finish=!0)),n.clicking){const a=t.retina.repulseModeDistance;if(!a||a<0)return;const r=Math.pow(a/6,3),l=e.mouse.clickPosition;if(void 0===l)return;const c=new s.Circle(l.x,l.y,r),o=t.particles.grid.query(c,t=>this.isEnabled(e,t));for(const e of o){const{dx:t,dy:a,distance:c}=s.getDistances(l,e.position),o=c**2,_=-r*i.speed/o;o<=r&&(this._trackInteractedParticle(e),n.particles.push(e),this._clickVec.x=t,this._clickVec.y=a,this._clickVec.length=_,e.velocity.setTo(this._clickVec))}}else if(!1===n.clicking){for(const e of n.particles)e.velocity.setTo(e.initialVelocity);n.particles=[]}};_hoverRepulse=e=>{const t=this.container,i=e.mouse.position,n=t.retina.repulseModeDistance;!n||n<0||!i||this._processRepulse(e,i,n,new s.Circle(i.x,i.y,n))};_processRepulse=(e,t,i,n,a)=>{const r=this.container,l=r.particles.grid.query(n,t=>this.isEnabled(e,t)),c=r.actualOptions.interactivity?.modes.repulse;if(!c)return;const{easing:o,speed:_,factor:p,maxSpeed:d}=c,u=this._pluginManager.getEasing(o),h=(a?.speed??_)*p;for(const e of l){const{dx:n,dy:a,distance:r}=s.getDistances(e.position,t),l=s.clamp(u(1-r/i)*h,0,d);this._normVec.x=r?n/r*l:h,this._normVec.y=r?a/r*l:h,this._trackInteractedParticle(e),e.position.addTo(this._normVec)}};_restoreParticles(){const e=this.container.actualOptions.interactivity?.modes.repulse?.restore;if(!e?.enable||!this._restoreData.size)return;const t=Date.now(),i=e.delay*s.millisecondsToSeconds,n=Math.max(.001,Math.min(1,e.speed));for(const[s,a]of this._restoreData){if(this._interactedThisFrame.has(s))continue;if(s.destroyed){this._restoreData.delete(s);continue}const r=a.target;if(t-a.lastInteractionTime<i)continue;e.follow&&s.options.move.enable&&(r.x+=s.velocity.x,r.y+=s.velocity.y,r.z+=s.velocity.z);const l=r.x-s.position.x,c=r.y-s.position.y,o=r.z-s.position.z;s.position.x+=l*n,s.position.y+=c*n,s.position.z+=o*n,Math.abs(l)<=.5&&Math.abs(c)<=.5&&(s.position.x=r.x,s.position.y=r.y,s.position.z=r.z,this._restoreData.delete(s))}}_singleSelectorRepulse=(e,i,n)=>{const a=this.container,r=a.actualOptions.interactivity?.modes.repulse;if(!r)return;const l=s.safeDocument().querySelectorAll(i);l.length&&l.forEach(i=>{const l=i,c=a.retina.pixelRatio,o={x:(l.offsetLeft+l.offsetWidth*s.half)*c,y:(l.offsetTop+l.offsetHeight*s.half)*c},_=l.offsetWidth*s.half*c,p=n.type===t.DivType.circle?new s.Circle(o.x,o.y,_):new s.Rectangle(l.offsetLeft*c,l.offsetTop*c,l.offsetWidth*c,l.offsetHeight*c),d=r.divs,u=t.divMode(d,l);this._processRepulse(e,o,_,p,u)})};_trackInteractedParticle(e){this._interactedThisFrame.add(e);const t=this.container.actualOptions.interactivity?.modes.repulse?.restore;if(!t?.enable)return;const s=Date.now();let i=this._restoreData.get(e);i||(i={target:e.position.copy(),lastInteractionTime:s},this._restoreData.set(e,i)),i.lastInteractionTime=s,t.follow&&e.options.move.enable&&(i.target.x+=e.velocity.x,i.target.y+=e.velocity.y,i.target.z+=e.velocity.z)}}async function c(e){e.checkVersion("4.0.0-beta.17"),await e.pluginManager.register(e=>{t.ensureInteractivityPluginLoaded(e);const s=e.pluginManager;s.addInteractor?.("externalRepulse",e=>Promise.resolve(new l(s,e)))})}const o=globalThis;o.__tsParticlesInternals=o.__tsParticlesInternals??{},o.loadExternalRepulseInteraction=c,e.Repulse=a,e.RepulseBase=i,e.RepulseDiv=n,e.loadExternalRepulseInteraction=c}),Object.assign(globalThis.window||globalThis,{loadExternalRepulseInteraction:(globalThis.__tsParticlesInternals.interactions.externalRepulse||{}).loadExternalRepulseInteraction}),delete(globalThis.window||globalThis).tsparticlesInternalExports;
@@ -1,11 +1,12 @@
1
1
  import { EasingType, type EasingTypeAlt, type IOptionLoader, type RecursivePartial } from "@tsparticles/engine";
2
- import type { IRepulseBase } from "../Interfaces/IRepulseBase.js";
2
+ import type { IRepulseBase, IRepulseRestore } from "../Interfaces/IRepulseBase.js";
3
3
  export declare abstract class RepulseBase implements IRepulseBase, IOptionLoader<IRepulseBase> {
4
4
  distance: number;
5
5
  duration: number;
6
6
  easing: EasingType | EasingTypeAlt;
7
7
  factor: number;
8
8
  maxSpeed: number;
9
+ restore: IRepulseRestore;
9
10
  speed: number;
10
11
  constructor();
11
12
  load(data?: RecursivePartial<IRepulseBase>): void;
@@ -1,9 +1,16 @@
1
1
  import type { EasingType, EasingTypeAlt } from "@tsparticles/engine";
2
+ export interface IRepulseRestore {
3
+ delay: number;
4
+ enable: boolean;
5
+ follow: boolean;
6
+ speed: number;
7
+ }
2
8
  export interface IRepulseBase {
3
9
  distance: number;
4
10
  duration: number;
5
11
  easing: EasingType | EasingTypeAlt;
6
12
  factor: number;
7
13
  maxSpeed: number;
14
+ restore: IRepulseRestore;
8
15
  speed: number;
9
16
  }
@@ -4,9 +4,11 @@ import type { IRepulseMode, RepulseContainer, RepulseMode } from "./Types.js";
4
4
  export declare class Repulser extends ExternalInteractorBase<RepulseContainer> {
5
5
  handleClickMode: (mode: string, interactivityData: IInteractivityData) => void;
6
6
  private readonly _clickVec;
7
+ private readonly _interactedThisFrame;
7
8
  private _maxDistance;
8
9
  private readonly _normVec;
9
10
  private readonly _pluginManager;
11
+ private readonly _restoreData;
10
12
  constructor(pluginManager: PluginManager, container: RepulseContainer);
11
13
  get maxDistance(): number;
12
14
  clear(): void;
@@ -18,5 +20,7 @@ export declare class Repulser extends ExternalInteractorBase<RepulseContainer> {
18
20
  private readonly _clickRepulse;
19
21
  private readonly _hoverRepulse;
20
22
  private readonly _processRepulse;
23
+ private _restoreParticles;
21
24
  private readonly _singleSelectorRepulse;
25
+ private _trackInteractedParticle;
22
26
  }
package/types/Types.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface IRepulseMode {
9
9
  export interface RepulseMode {
10
10
  repulse?: Repulse;
11
11
  }
12
- interface IContainerRepulse {
12
+ export interface IContainerRepulse {
13
13
  clicking?: boolean;
14
14
  count?: number;
15
15
  finish?: boolean;
@@ -22,4 +22,3 @@ export type RepulseContainer = InteractivityContainer & {
22
22
  repulseModeDistance?: number;
23
23
  };
24
24
  };
25
- export {};