@tsparticles/interaction-external-repulse 3.0.0-alpha.1 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cjs/Repulser.js CHANGED
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.Repulser = void 0;
13
4
  const engine_1 = require("@tsparticles/engine");
@@ -15,36 +6,113 @@ const Repulse_1 = require("./Options/Classes/Repulse");
15
6
  class Repulser extends engine_1.ExternalInteractorBase {
16
7
  constructor(engine, container) {
17
8
  super(container);
9
+ this._clickRepulse = () => {
10
+ const container = this.container, repulseOptions = container.actualOptions.interactivity.modes.repulse;
11
+ if (!repulseOptions) {
12
+ return;
13
+ }
14
+ const repulse = container.repulse || { particles: [] };
15
+ if (!repulse.finish) {
16
+ if (!repulse.count) {
17
+ repulse.count = 0;
18
+ }
19
+ repulse.count++;
20
+ if (repulse.count === container.particles.count) {
21
+ repulse.finish = true;
22
+ }
23
+ }
24
+ if (repulse.clicking) {
25
+ const repulseDistance = container.retina.repulseModeDistance;
26
+ if (!repulseDistance || repulseDistance < 0) {
27
+ return;
28
+ }
29
+ const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
30
+ if (mouseClickPos === undefined) {
31
+ return;
32
+ }
33
+ const range = new engine_1.Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
34
+ for (const particle of query) {
35
+ const { dx, dy, distance } = (0, engine_1.getDistances)(mouseClickPos, particle.position), d = distance ** 2, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
36
+ if (d <= repulseRadius) {
37
+ repulse.particles.push(particle);
38
+ const vect = engine_1.Vector.create(dx, dy);
39
+ vect.length = force;
40
+ particle.velocity.setTo(vect);
41
+ }
42
+ }
43
+ }
44
+ else if (repulse.clicking === false) {
45
+ for (const particle of repulse.particles) {
46
+ particle.velocity.setTo(particle.initialVelocity);
47
+ }
48
+ repulse.particles = [];
49
+ }
50
+ };
51
+ this._hoverRepulse = () => {
52
+ const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
53
+ if (!repulseRadius || repulseRadius < 0 || !mousePos) {
54
+ return;
55
+ }
56
+ this._processRepulse(mousePos, repulseRadius, new engine_1.Circle(mousePos.x, mousePos.y, repulseRadius));
57
+ };
58
+ this._processRepulse = (position, repulseRadius, area, divRepulse) => {
59
+ const container = this.container, query = container.particles.quadTree.query(area, (p) => this.isEnabled(p)), repulseOptions = container.actualOptions.interactivity.modes.repulse;
60
+ if (!repulseOptions) {
61
+ return;
62
+ }
63
+ for (const particle of query) {
64
+ const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position), velocity = (divRepulse?.speed ?? repulseOptions.speed) * repulseOptions.factor, repulseFactor = (0, engine_1.clamp)((0, engine_1.getEasing)(repulseOptions.easing)(1 - distance / repulseRadius) * velocity, 0, repulseOptions.maxSpeed), normVec = engine_1.Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
65
+ particle.position.addTo(normVec);
66
+ }
67
+ };
68
+ this._singleSelectorRepulse = (selector, div) => {
69
+ const container = this.container, repulse = container.actualOptions.interactivity.modes.repulse;
70
+ if (!repulse) {
71
+ return;
72
+ }
73
+ const query = document.querySelectorAll(selector);
74
+ if (!query.length) {
75
+ return;
76
+ }
77
+ query.forEach((item) => {
78
+ const elem = item, pxRatio = container.retina.pixelRatio, pos = {
79
+ x: (elem.offsetLeft + elem.offsetWidth / 2) * pxRatio,
80
+ y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
81
+ }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
82
+ ? new engine_1.Circle(pos.x, pos.y, repulseRadius)
83
+ : 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);
84
+ this._processRepulse(pos, repulseRadius, area, divRepulse);
85
+ });
86
+ };
18
87
  this._engine = engine;
19
88
  if (!container.repulse) {
20
89
  container.repulse = { particles: [] };
21
90
  }
22
91
  this.handleClickMode = (mode) => {
23
- const options = this.container.actualOptions, repulse = options.interactivity.modes.repulse;
24
- if (!repulse || mode !== "repulse") {
92
+ const options = this.container.actualOptions, repulseOpts = options.interactivity.modes.repulse;
93
+ if (!repulseOpts || mode !== "repulse") {
25
94
  return;
26
95
  }
27
96
  if (!container.repulse) {
28
97
  container.repulse = { particles: [] };
29
98
  }
30
- container.repulse.clicking = true;
31
- container.repulse.count = 0;
99
+ const repulse = container.repulse;
100
+ repulse.clicking = true;
101
+ repulse.count = 0;
32
102
  for (const particle of container.repulse.particles) {
33
103
  if (!this.isEnabled(particle)) {
34
104
  continue;
35
105
  }
36
106
  particle.velocity.setTo(particle.initialVelocity);
37
107
  }
38
- container.repulse.particles = [];
39
- container.repulse.finish = false;
108
+ repulse.particles = [];
109
+ repulse.finish = false;
40
110
  setTimeout(() => {
41
- if (!container.destroyed) {
42
- if (!container.repulse) {
43
- container.repulse = { particles: [] };
44
- }
45
- container.repulse.clicking = false;
111
+ if (container.destroyed) {
112
+ return;
46
113
  }
47
- }, repulse.duration * 1000);
114
+ repulse.clicking = false;
115
+ }, repulseOpts.duration * 1000);
48
116
  };
49
117
  }
50
118
  clear() {
@@ -56,27 +124,24 @@ class Repulser extends engine_1.ExternalInteractorBase {
56
124
  }
57
125
  container.retina.repulseModeDistance = repulse.distance * container.retina.pixelRatio;
58
126
  }
59
- interact() {
60
- return __awaiter(this, void 0, void 0, function* () {
61
- const container = this.container, options = container.actualOptions, mouseMoveStatus = container.interactivity.status === engine_1.mouseMoveEvent, events = options.interactivity.events, hoverEnabled = events.onHover.enable, hoverMode = events.onHover.mode, clickEnabled = events.onClick.enable, clickMode = events.onClick.mode, divs = events.onDiv;
62
- if (mouseMoveStatus && hoverEnabled && (0, engine_1.isInArray)("repulse", hoverMode)) {
63
- this.hoverRepulse();
64
- }
65
- else if (clickEnabled && (0, engine_1.isInArray)("repulse", clickMode)) {
66
- this.clickRepulse();
67
- }
68
- else {
69
- (0, engine_1.divModeExecute)("repulse", divs, (selector, div) => this.singleSelectorRepulse(selector, div));
70
- }
71
- });
127
+ async interact() {
128
+ const container = this.container, options = container.actualOptions, mouseMoveStatus = container.interactivity.status === engine_1.mouseMoveEvent, events = options.interactivity.events, hover = events.onHover, hoverEnabled = hover.enable, hoverMode = hover.mode, click = events.onClick, clickEnabled = click.enable, clickMode = click.mode, divs = events.onDiv;
129
+ if (mouseMoveStatus && hoverEnabled && (0, engine_1.isInArray)("repulse", hoverMode)) {
130
+ this._hoverRepulse();
131
+ }
132
+ else if (clickEnabled && (0, engine_1.isInArray)("repulse", clickMode)) {
133
+ this._clickRepulse();
134
+ }
135
+ else {
136
+ (0, engine_1.divModeExecute)("repulse", divs, (selector, div) => this._singleSelectorRepulse(selector, div));
137
+ }
72
138
  }
73
139
  isEnabled(particle) {
74
- var _a;
75
- const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = ((_a = particle === null || particle === void 0 ? void 0 : particle.interactivity) !== null && _a !== void 0 ? _a : options.interactivity).events, divs = events.onDiv, divRepulse = (0, engine_1.isDivModeEnabled)("repulse", divs);
76
- if (!(divRepulse || (events.onHover.enable && mouse.position) || (events.onClick.enable && mouse.clickPosition))) {
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 = (0, engine_1.isDivModeEnabled)("repulse", divs);
141
+ if (!(divRepulse || (hover.enable && mouse.position) || (click.enable && mouse.clickPosition))) {
77
142
  return false;
78
143
  }
79
- const hoverMode = events.onHover.mode, clickMode = events.onClick.mode;
144
+ const hoverMode = hover.mode, clickMode = click.mode;
80
145
  return (0, engine_1.isInArray)("repulse", hoverMode) || (0, engine_1.isInArray)("repulse", clickMode) || divRepulse;
81
146
  }
82
147
  loadModeOptions(options, ...sources) {
@@ -84,91 +149,10 @@ class Repulser extends engine_1.ExternalInteractorBase {
84
149
  options.repulse = new Repulse_1.Repulse();
85
150
  }
86
151
  for (const source of sources) {
87
- options.repulse.load(source === null || source === void 0 ? void 0 : source.repulse);
152
+ options.repulse.load(source?.repulse);
88
153
  }
89
154
  }
90
155
  reset() {
91
156
  }
92
- clickRepulse() {
93
- const container = this.container, repulse = container.actualOptions.interactivity.modes.repulse;
94
- if (!repulse) {
95
- return;
96
- }
97
- if (!container.repulse) {
98
- container.repulse = { particles: [] };
99
- }
100
- if (!container.repulse.finish) {
101
- if (!container.repulse.count) {
102
- container.repulse.count = 0;
103
- }
104
- container.repulse.count++;
105
- if (container.repulse.count === container.particles.count) {
106
- container.repulse.finish = true;
107
- }
108
- }
109
- if (container.repulse.clicking) {
110
- const repulseDistance = container.retina.repulseModeDistance;
111
- if (!repulseDistance || repulseDistance < 0) {
112
- return;
113
- }
114
- const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
115
- if (mouseClickPos === undefined) {
116
- return;
117
- }
118
- const range = new engine_1.Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
119
- for (const particle of query) {
120
- const { dx, dy, distance } = (0, engine_1.getDistances)(mouseClickPos, particle.position), d = Math.pow(distance, 2), velocity = repulse.speed, force = (-repulseRadius * velocity) / d;
121
- if (d <= repulseRadius) {
122
- container.repulse.particles.push(particle);
123
- const vect = engine_1.Vector.create(dx, dy);
124
- vect.length = force;
125
- particle.velocity.setTo(vect);
126
- }
127
- }
128
- }
129
- else if (container.repulse.clicking === false) {
130
- for (const particle of container.repulse.particles) {
131
- particle.velocity.setTo(particle.initialVelocity);
132
- }
133
- container.repulse.particles = [];
134
- }
135
- }
136
- hoverRepulse() {
137
- const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
138
- if (!repulseRadius || repulseRadius < 0 || !mousePos) {
139
- return;
140
- }
141
- this.processRepulse(mousePos, repulseRadius, new engine_1.Circle(mousePos.x, mousePos.y, repulseRadius));
142
- }
143
- processRepulse(position, repulseRadius, area, divRepulse) {
144
- var _a;
145
- const container = this.container, query = container.particles.quadTree.query(area, (p) => this.isEnabled(p)), repulseOptions = container.actualOptions.interactivity.modes.repulse;
146
- if (!repulseOptions) {
147
- return;
148
- }
149
- for (const particle of query) {
150
- const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position), velocity = ((_a = divRepulse === null || divRepulse === void 0 ? void 0 : divRepulse.speed) !== null && _a !== void 0 ? _a : repulseOptions.speed) * repulseOptions.factor, repulseFactor = (0, engine_1.clamp)((0, engine_1.getEasing)(repulseOptions.easing)(1 - distance / repulseRadius) * velocity, 0, repulseOptions.maxSpeed), normVec = engine_1.Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
151
- particle.position.addTo(normVec);
152
- }
153
- }
154
- singleSelectorRepulse(selector, div) {
155
- const container = this.container, repulse = container.actualOptions.interactivity.modes.repulse;
156
- if (!repulse) {
157
- return;
158
- }
159
- const query = document.querySelectorAll(selector);
160
- if (!query.length) {
161
- return;
162
- }
163
- query.forEach((item) => {
164
- const elem = item, pxRatio = container.retina.pixelRatio, pos = {
165
- x: (elem.offsetLeft + elem.offsetWidth / 2) * pxRatio,
166
- y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
167
- }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
168
- ? new engine_1.Circle(pos.x, pos.y, repulseRadius)
169
- : 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);
170
- this.processRepulse(pos, repulseRadius, area, divRepulse);
171
- });
172
- }
173
157
  }
174
158
  exports.Repulser = Repulser;
package/cjs/index.js CHANGED
@@ -13,22 +13,11 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
13
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18
- return new (P || (P = Promise))(function (resolve, reject) {
19
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22
- step((generator = generator.apply(thisArg, _arguments || [])).next());
23
- });
24
- };
25
16
  Object.defineProperty(exports, "__esModule", { value: true });
26
17
  exports.loadExternalRepulseInteraction = void 0;
27
18
  const Repulser_1 = require("./Repulser");
28
- function loadExternalRepulseInteraction(engine) {
29
- return __awaiter(this, void 0, void 0, function* () {
30
- yield engine.addInteractor("externalRepulse", (container) => new Repulser_1.Repulser(engine, container));
31
- });
19
+ async function loadExternalRepulseInteraction(engine, refresh = true) {
20
+ await engine.addInteractor("externalRepulse", (container) => new Repulser_1.Repulser(engine, container), refresh);
32
21
  }
33
22
  exports.loadExternalRepulseInteraction = loadExternalRepulseInteraction;
34
23
  __exportStar(require("./Options/Classes/RepulseBase"), exports);
@@ -1,6 +1,6 @@
1
+ import { executeOnSingleOrMultiple, } from "@tsparticles/engine";
1
2
  import { RepulseBase } from "./RepulseBase";
2
3
  import { RepulseDiv } from "./RepulseDiv";
3
- import { executeOnSingleOrMultiple } from "@tsparticles/engine";
4
4
  export class Repulse extends RepulseBase {
5
5
  load(data) {
6
6
  super.load(data);
@@ -1,24 +1,14 @@
1
1
  import { RepulseBase } from "./RepulseBase";
2
- import { executeOnSingleOrMultiple } from "@tsparticles/engine";
3
2
  export class RepulseDiv extends RepulseBase {
4
3
  constructor() {
5
4
  super();
6
5
  this.selectors = [];
7
6
  }
8
- get ids() {
9
- return executeOnSingleOrMultiple(this.selectors, (t) => t.replace("#", ""));
10
- }
11
- set ids(value) {
12
- this.selectors = executeOnSingleOrMultiple(value, (t) => `#${t}`);
13
- }
14
7
  load(data) {
15
8
  super.load(data);
16
9
  if (!data) {
17
10
  return;
18
11
  }
19
- if (data.ids !== undefined) {
20
- this.ids = data.ids;
21
- }
22
12
  if (data.selectors !== undefined) {
23
13
  this.selectors = data.selectors;
24
14
  }
package/esm/Repulser.js CHANGED
@@ -3,36 +3,113 @@ import { Repulse } from "./Options/Classes/Repulse";
3
3
  export class Repulser extends ExternalInteractorBase {
4
4
  constructor(engine, container) {
5
5
  super(container);
6
+ this._clickRepulse = () => {
7
+ const container = this.container, repulseOptions = container.actualOptions.interactivity.modes.repulse;
8
+ if (!repulseOptions) {
9
+ return;
10
+ }
11
+ const repulse = container.repulse || { particles: [] };
12
+ if (!repulse.finish) {
13
+ if (!repulse.count) {
14
+ repulse.count = 0;
15
+ }
16
+ repulse.count++;
17
+ if (repulse.count === container.particles.count) {
18
+ repulse.finish = true;
19
+ }
20
+ }
21
+ if (repulse.clicking) {
22
+ const repulseDistance = container.retina.repulseModeDistance;
23
+ if (!repulseDistance || repulseDistance < 0) {
24
+ return;
25
+ }
26
+ const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
27
+ if (mouseClickPos === undefined) {
28
+ return;
29
+ }
30
+ const range = new Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
31
+ for (const particle of query) {
32
+ const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** 2, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
33
+ if (d <= repulseRadius) {
34
+ repulse.particles.push(particle);
35
+ const vect = Vector.create(dx, dy);
36
+ vect.length = force;
37
+ particle.velocity.setTo(vect);
38
+ }
39
+ }
40
+ }
41
+ else if (repulse.clicking === false) {
42
+ for (const particle of repulse.particles) {
43
+ particle.velocity.setTo(particle.initialVelocity);
44
+ }
45
+ repulse.particles = [];
46
+ }
47
+ };
48
+ this._hoverRepulse = () => {
49
+ const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
50
+ if (!repulseRadius || repulseRadius < 0 || !mousePos) {
51
+ return;
52
+ }
53
+ this._processRepulse(mousePos, repulseRadius, new Circle(mousePos.x, mousePos.y, repulseRadius));
54
+ };
55
+ this._processRepulse = (position, repulseRadius, area, divRepulse) => {
56
+ const container = this.container, query = container.particles.quadTree.query(area, (p) => this.isEnabled(p)), repulseOptions = container.actualOptions.interactivity.modes.repulse;
57
+ if (!repulseOptions) {
58
+ return;
59
+ }
60
+ for (const particle of query) {
61
+ const { dx, dy, distance } = getDistances(particle.position, position), velocity = (divRepulse?.speed ?? repulseOptions.speed) * repulseOptions.factor, repulseFactor = clamp(getEasing(repulseOptions.easing)(1 - distance / repulseRadius) * velocity, 0, repulseOptions.maxSpeed), normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
62
+ particle.position.addTo(normVec);
63
+ }
64
+ };
65
+ this._singleSelectorRepulse = (selector, div) => {
66
+ const container = this.container, repulse = container.actualOptions.interactivity.modes.repulse;
67
+ if (!repulse) {
68
+ return;
69
+ }
70
+ const query = document.querySelectorAll(selector);
71
+ if (!query.length) {
72
+ return;
73
+ }
74
+ query.forEach((item) => {
75
+ const elem = item, pxRatio = container.retina.pixelRatio, pos = {
76
+ x: (elem.offsetLeft + elem.offsetWidth / 2) * pxRatio,
77
+ y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
78
+ }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
79
+ ? new Circle(pos.x, pos.y, repulseRadius)
80
+ : new Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), divs = repulse.divs, divRepulse = divMode(divs, elem);
81
+ this._processRepulse(pos, repulseRadius, area, divRepulse);
82
+ });
83
+ };
6
84
  this._engine = engine;
7
85
  if (!container.repulse) {
8
86
  container.repulse = { particles: [] };
9
87
  }
10
88
  this.handleClickMode = (mode) => {
11
- const options = this.container.actualOptions, repulse = options.interactivity.modes.repulse;
12
- if (!repulse || mode !== "repulse") {
89
+ const options = this.container.actualOptions, repulseOpts = options.interactivity.modes.repulse;
90
+ if (!repulseOpts || mode !== "repulse") {
13
91
  return;
14
92
  }
15
93
  if (!container.repulse) {
16
94
  container.repulse = { particles: [] };
17
95
  }
18
- container.repulse.clicking = true;
19
- container.repulse.count = 0;
96
+ const repulse = container.repulse;
97
+ repulse.clicking = true;
98
+ repulse.count = 0;
20
99
  for (const particle of container.repulse.particles) {
21
100
  if (!this.isEnabled(particle)) {
22
101
  continue;
23
102
  }
24
103
  particle.velocity.setTo(particle.initialVelocity);
25
104
  }
26
- container.repulse.particles = [];
27
- container.repulse.finish = false;
105
+ repulse.particles = [];
106
+ repulse.finish = false;
28
107
  setTimeout(() => {
29
- if (!container.destroyed) {
30
- if (!container.repulse) {
31
- container.repulse = { particles: [] };
32
- }
33
- container.repulse.clicking = false;
108
+ if (container.destroyed) {
109
+ return;
34
110
  }
35
- }, repulse.duration * 1000);
111
+ repulse.clicking = false;
112
+ }, repulseOpts.duration * 1000);
36
113
  };
37
114
  }
38
115
  clear() {
@@ -45,24 +122,23 @@ export class Repulser extends ExternalInteractorBase {
45
122
  container.retina.repulseModeDistance = repulse.distance * container.retina.pixelRatio;
46
123
  }
47
124
  async interact() {
48
- const container = this.container, options = container.actualOptions, mouseMoveStatus = container.interactivity.status === mouseMoveEvent, events = options.interactivity.events, hoverEnabled = events.onHover.enable, hoverMode = events.onHover.mode, clickEnabled = events.onClick.enable, clickMode = events.onClick.mode, divs = events.onDiv;
125
+ const container = this.container, options = container.actualOptions, mouseMoveStatus = container.interactivity.status === mouseMoveEvent, events = options.interactivity.events, hover = events.onHover, hoverEnabled = hover.enable, hoverMode = hover.mode, click = events.onClick, clickEnabled = click.enable, clickMode = click.mode, divs = events.onDiv;
49
126
  if (mouseMoveStatus && hoverEnabled && isInArray("repulse", hoverMode)) {
50
- this.hoverRepulse();
127
+ this._hoverRepulse();
51
128
  }
52
129
  else if (clickEnabled && isInArray("repulse", clickMode)) {
53
- this.clickRepulse();
130
+ this._clickRepulse();
54
131
  }
55
132
  else {
56
- divModeExecute("repulse", divs, (selector, div) => this.singleSelectorRepulse(selector, div));
133
+ divModeExecute("repulse", divs, (selector, div) => this._singleSelectorRepulse(selector, div));
57
134
  }
58
135
  }
59
136
  isEnabled(particle) {
60
- var _a;
61
- const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = ((_a = particle === null || particle === void 0 ? void 0 : particle.interactivity) !== null && _a !== void 0 ? _a : options.interactivity).events, divs = events.onDiv, divRepulse = isDivModeEnabled("repulse", divs);
62
- if (!(divRepulse || (events.onHover.enable && mouse.position) || (events.onClick.enable && mouse.clickPosition))) {
137
+ 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("repulse", divs);
138
+ if (!(divRepulse || (hover.enable && mouse.position) || (click.enable && mouse.clickPosition))) {
63
139
  return false;
64
140
  }
65
- const hoverMode = events.onHover.mode, clickMode = events.onClick.mode;
141
+ const hoverMode = hover.mode, clickMode = click.mode;
66
142
  return isInArray("repulse", hoverMode) || isInArray("repulse", clickMode) || divRepulse;
67
143
  }
68
144
  loadModeOptions(options, ...sources) {
@@ -70,90 +146,9 @@ export class Repulser extends ExternalInteractorBase {
70
146
  options.repulse = new Repulse();
71
147
  }
72
148
  for (const source of sources) {
73
- options.repulse.load(source === null || source === void 0 ? void 0 : source.repulse);
149
+ options.repulse.load(source?.repulse);
74
150
  }
75
151
  }
76
152
  reset() {
77
153
  }
78
- clickRepulse() {
79
- const container = this.container, repulse = container.actualOptions.interactivity.modes.repulse;
80
- if (!repulse) {
81
- return;
82
- }
83
- if (!container.repulse) {
84
- container.repulse = { particles: [] };
85
- }
86
- if (!container.repulse.finish) {
87
- if (!container.repulse.count) {
88
- container.repulse.count = 0;
89
- }
90
- container.repulse.count++;
91
- if (container.repulse.count === container.particles.count) {
92
- container.repulse.finish = true;
93
- }
94
- }
95
- if (container.repulse.clicking) {
96
- const repulseDistance = container.retina.repulseModeDistance;
97
- if (!repulseDistance || repulseDistance < 0) {
98
- return;
99
- }
100
- const repulseRadius = Math.pow(repulseDistance / 6, 3), mouseClickPos = container.interactivity.mouse.clickPosition;
101
- if (mouseClickPos === undefined) {
102
- return;
103
- }
104
- const range = new Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.quadTree.query(range, (p) => this.isEnabled(p));
105
- for (const particle of query) {
106
- const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** 2, velocity = repulse.speed, force = (-repulseRadius * velocity) / d;
107
- if (d <= repulseRadius) {
108
- container.repulse.particles.push(particle);
109
- const vect = Vector.create(dx, dy);
110
- vect.length = force;
111
- particle.velocity.setTo(vect);
112
- }
113
- }
114
- }
115
- else if (container.repulse.clicking === false) {
116
- for (const particle of container.repulse.particles) {
117
- particle.velocity.setTo(particle.initialVelocity);
118
- }
119
- container.repulse.particles = [];
120
- }
121
- }
122
- hoverRepulse() {
123
- const container = this.container, mousePos = container.interactivity.mouse.position, repulseRadius = container.retina.repulseModeDistance;
124
- if (!repulseRadius || repulseRadius < 0 || !mousePos) {
125
- return;
126
- }
127
- this.processRepulse(mousePos, repulseRadius, new Circle(mousePos.x, mousePos.y, repulseRadius));
128
- }
129
- processRepulse(position, repulseRadius, area, divRepulse) {
130
- var _a;
131
- const container = this.container, query = container.particles.quadTree.query(area, (p) => this.isEnabled(p)), repulseOptions = container.actualOptions.interactivity.modes.repulse;
132
- if (!repulseOptions) {
133
- return;
134
- }
135
- for (const particle of query) {
136
- const { dx, dy, distance } = getDistances(particle.position, position), velocity = ((_a = divRepulse === null || divRepulse === void 0 ? void 0 : divRepulse.speed) !== null && _a !== void 0 ? _a : repulseOptions.speed) * repulseOptions.factor, repulseFactor = clamp(getEasing(repulseOptions.easing)(1 - distance / repulseRadius) * velocity, 0, repulseOptions.maxSpeed), normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * repulseFactor, distance === 0 ? velocity : (dy / distance) * repulseFactor);
137
- particle.position.addTo(normVec);
138
- }
139
- }
140
- singleSelectorRepulse(selector, div) {
141
- const container = this.container, repulse = container.actualOptions.interactivity.modes.repulse;
142
- if (!repulse) {
143
- return;
144
- }
145
- const query = document.querySelectorAll(selector);
146
- if (!query.length) {
147
- return;
148
- }
149
- query.forEach((item) => {
150
- const elem = item, pxRatio = container.retina.pixelRatio, pos = {
151
- x: (elem.offsetLeft + elem.offsetWidth / 2) * pxRatio,
152
- y: (elem.offsetTop + elem.offsetHeight / 2) * pxRatio,
153
- }, repulseRadius = (elem.offsetWidth / 2) * pxRatio, area = div.type === "circle"
154
- ? new Circle(pos.x, pos.y, repulseRadius)
155
- : new Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), divs = repulse.divs, divRepulse = divMode(divs, elem);
156
- this.processRepulse(pos, repulseRadius, area, divRepulse);
157
- });
158
- }
159
154
  }
package/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Repulser } from "./Repulser";
2
- export async function loadExternalRepulseInteraction(engine) {
3
- await engine.addInteractor("externalRepulse", (container) => new Repulser(engine, container));
2
+ export async function loadExternalRepulseInteraction(engine, refresh = true) {
3
+ await engine.addInteractor("externalRepulse", (container) => new Repulser(engine, container), refresh);
4
4
  }
5
5
  export * from "./Options/Classes/RepulseBase";
6
6
  export * from "./Options/Classes/RepulseDiv";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsparticles/interaction-external-repulse",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.0-beta.0",
4
4
  "description": "tsParticles repulse external interaction",
5
5
  "homepage": "https://particles.js.org",
6
6
  "repository": {
@@ -73,10 +73,11 @@
73
73
  "unpkg": "tsparticles.interaction.external.repulse.min.js",
74
74
  "module": "esm/index.js",
75
75
  "types": "types/index.d.ts",
76
+ "sideEffects": false,
77
+ "dependencies": {
78
+ "@tsparticles/engine": "^3.0.0-beta.0"
79
+ },
76
80
  "publishConfig": {
77
81
  "access": "public"
78
- },
79
- "dependencies": {
80
- "@tsparticles/engine": "^3.0.0-alpha.1"
81
82
  }
82
- }
83
+ }