@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.
@@ -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 || { particles: [] };
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 < 0) {
24
+ if (!repulseDistance || repulseDistance < minDistance) {
25
25
  return;
26
26
  }
27
- const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
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 ** 2, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
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 < 0 || !mousePos) {
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(1 - distance / repulseRadius) * velocity, 0, maxSpeed), normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
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 / 2) * pxRatio,
79
- y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
80
- }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
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 * 1000);
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 || { particles: [] };
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 < 0) {
27
+ if (!repulseDistance || repulseDistance < minDistance) {
28
28
  return;
29
29
  }
30
- const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
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 ** 2, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
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 < 0 || !mousePos) {
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(1 - distance / repulseRadius) * velocity, 0, maxSpeed), normVec = engine_1.Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
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 / 2) * pxRatio,
82
- y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
83
- }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
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 * 1000);
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 || { particles: [] };
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 < 0) {
24
+ if (!repulseDistance || repulseDistance < minDistance) {
25
25
  return;
26
26
  }
27
- const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
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 ** 2, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
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 < 0 || !mousePos) {
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(1 - distance / repulseRadius) * velocity, 0, maxSpeed), normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
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 / 2) * pxRatio,
79
- y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
80
- }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
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 * 1000);
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.2",
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.2"
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 Dec 2023 at 17:39]</title>
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":9560,"parsedSize":13456,"gzipSize":3351,"groups":[{"label":"dist/browser","path":"./dist/browser","statSize":9518,"groups":[{"id":26,"label":"index.js + 4 modules (concatenated)","path":"./dist/browser/index.js + 4 modules (concatenated)","statSize":9518,"parsedSize":13456,"gzipSize":3351,"concatenated":true,"groups":[{"label":"dist/browser","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser","statSize":9518,"groups":[{"id":null,"label":"index.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/index.js","statSize":528,"parsedSize":746,"gzipSize":185,"inaccurateSizes":true},{"id":null,"label":"Repulser.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/Repulser.js","statSize":7517,"parsedSize":10627,"gzipSize":2646,"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":602,"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":1030,"gzipSize":256,"inaccurateSizes":true},{"id":null,"label":"RepulseDiv.js","path":"./dist/browser/index.js + 4 modules (concatenated)/dist/browser/Options/Classes/RepulseDiv.js","statSize":318,"parsedSize":449,"gzipSize":111,"inaccurateSizes":true}],"parsedSize":2082,"gzipSize":518,"inaccurateSizes":true}],"parsedSize":13456,"gzipSize":3351,"inaccurateSizes":true}]}],"parsedSize":13456,"gzipSize":3351},{"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}}];
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.2
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 < 0) {
205
+ if (!repulseDistance || repulseDistance < minDistance) {
198
206
  return;
199
207
  }
200
- const repulseRadius = Math.pow(repulseDistance / 6, 3),
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 ** 2,
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 < 0 || !mousePos) {
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(1 - distance / repulseRadius) * velocity, 0, maxSpeed),
261
- normVec = engine_root_window_.Vector.create(distance === 0 ? velocity : dx / distance * repulseFactor, distance === 0 ? velocity : dy / distance * repulseFactor);
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 / 2) * pxRatio,
280
- y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio
287
+ x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
288
+ y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio
281
289
  },
282
- repulseRadius = elem.offsetWidth / 2 * pxRatio,
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 * 1000);
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||{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(0===r?f:o/r*c,0===r?f:n/r*c);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+n.offsetWidth/2)*r,y:(n.offsetTop+n.offsetHeight/2)*r},a=n.offsetWidth/2*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=e=>{const t=this.container.actualOptions.interactivity.modes.repulse;if(!t||e!==r)return;i.repulse||(i.repulse={particles:[]});const s=i.repulse;s.clicking=!0,s.count=0;for(const e of i.repulse.particles)this.isEnabled(e)&&e.velocity.setTo(e.initialVelocity);s.particles=[],s.finish=!1,setTimeout((()=>{i.destroyed||(s.clicking=!1)}),1e3*t.duration)}}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)))}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})()));
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.2 by Matteo Bruni */
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 type IRepulseMode = {
5
+ export interface IRepulseMode {
6
6
  repulse: IRepulse;
7
- };
8
- export type RepulseMode = {
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 || { particles: [] };
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 < 0) {
36
+ if (!repulseDistance || repulseDistance < minDistance) {
37
37
  return;
38
38
  }
39
- const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
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 ** 2, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
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 < 0 || !mousePos) {
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(1 - distance / repulseRadius) * velocity, 0, maxSpeed), normVec = engine_1.Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
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 / 2) * pxRatio,
91
- y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
92
- }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
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 * 1000);
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;