@tsparticles/interaction-external-attract 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/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  # tsParticles External Attraction Interaction
4
4
 
5
- [![jsDelivr](https://data.jsdelivr.com/v1/package/npm/tsparticles-interaction-external-attract/badge)](https://www.jsdelivr.com/package/npm/tsparticles-interaction-external-attract)
6
- [![npmjs](https://badge.fury.io/js/tsparticles-interaction-external-attract.svg)](https://www.npmjs.com/package/tsparticles-interaction-external-attract)
7
- [![npmjs](https://img.shields.io/npm/dt/tsparticles-interaction-external-attract)](https://www.npmjs.com/package/tsparticles-interaction-external-attract) [![GitHub Sponsors](https://img.shields.io/github/sponsors/matteobruni)](https://github.com/sponsors/matteobruni)
5
+ [![jsDelivr](https://data.jsdelivr.com/v1/package/npm/@tsparticles/interaction-external-attract/badge)](https://www.jsdelivr.com/package/npm/@tsparticles/interaction-external-attract)
6
+ [![npmjs](https://badge.fury.io/js/@tsparticles/interaction-external-attract.svg)](https://www.npmjs.com/package/@tsparticles/interaction-external-attract)
7
+ [![npmjs](https://img.shields.io/npm/dt/@tsparticles/interaction-external-attract)](https://www.npmjs.com/package/@tsparticles/interaction-external-attract) [![GitHub Sponsors](https://img.shields.io/github/sponsors/matteobruni)](https://github.com/sponsors/matteobruni)
8
8
 
9
9
  [tsParticles](https://github.com/matteobruni/tsparticles) interaction plugin for attract effect around mouse or HTML
10
10
  elements.
@@ -27,14 +27,16 @@ loadExternalAttractInteraction;
27
27
  Once the scripts are loaded you can set up `tsParticles` and the interaction plugin like this:
28
28
 
29
29
  ```javascript
30
- loadExternalAttractInteraction(tsParticles);
31
-
32
- tsParticles.load({
33
- id: "tsparticles",
34
- options: {
35
- /* options */
36
- },
37
- });
30
+ (async () => {
31
+ await loadExternalAttractInteraction(tsParticles);
32
+
33
+ await tsParticles.load({
34
+ id: "tsparticles",
35
+ options: {
36
+ /* options */
37
+ },
38
+ });
39
+ })();
38
40
  ```
39
41
 
40
42
  ### ESM / CommonJS
@@ -42,29 +44,33 @@ tsParticles.load({
42
44
  This package is compatible also with ES or CommonJS modules, firstly this needs to be installed, like this:
43
45
 
44
46
  ```shell
45
- $ npm install tsparticles-interaction-external-attract
47
+ $ npm install @tsparticles/interaction-external-attract
46
48
  ```
47
49
 
48
50
  or
49
51
 
50
52
  ```shell
51
- $ yarn add tsparticles-interaction-external-attract
53
+ $ yarn add @tsparticles/interaction-external-attract
52
54
  ```
53
55
 
54
56
  Then you need to import it in the app, like this:
55
57
 
56
58
  ```javascript
57
- const { tsParticles } = require("tsparticles-engine");
58
- const { loadExternalAttractInteraction } = require("tsparticles-interaction-external-attract");
59
+ const { tsParticles } = require("@tsparticles/engine");
60
+ const { loadExternalAttractInteraction } = require("@tsparticles/interaction-external-attract");
59
61
 
60
- loadExternalAttractInteraction(tsParticles);
62
+ (async () => {
63
+ await loadExternalAttractInteraction(tsParticles);
64
+ })();
61
65
  ```
62
66
 
63
67
  or
64
68
 
65
69
  ```javascript
66
- import { tsParticles } from "tsparticles-engine";
67
- import { loadExternalAttractInteraction } from "tsparticles-interaction-external-attract";
70
+ import { tsParticles } from "@tsparticles/engine";
71
+ import { loadExternalAttractInteraction } from "@tsparticles/interaction-external-attract";
68
72
 
69
- loadExternalAttractInteraction(tsParticles);
73
+ (async () => {
74
+ await loadExternalAttractInteraction(tsParticles);
75
+ })();
70
76
  ```
@@ -3,6 +3,54 @@ import { Attract } from "./Options/Classes/Attract";
3
3
  export class Attractor extends ExternalInteractorBase {
4
4
  constructor(engine, container) {
5
5
  super(container);
6
+ this._clickAttract = () => {
7
+ const container = this.container;
8
+ if (!container.attract) {
9
+ container.attract = { particles: [] };
10
+ }
11
+ const { attract } = container;
12
+ if (!attract.finish) {
13
+ if (!attract.count) {
14
+ attract.count = 0;
15
+ }
16
+ attract.count++;
17
+ if (attract.count === container.particles.count) {
18
+ attract.finish = true;
19
+ }
20
+ }
21
+ if (attract.clicking) {
22
+ const mousePos = container.interactivity.mouse.clickPosition, attractRadius = container.retina.attractModeDistance;
23
+ if (!attractRadius || attractRadius < 0 || !mousePos) {
24
+ return;
25
+ }
26
+ this._processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
27
+ }
28
+ else if (attract.clicking === false) {
29
+ attract.particles = [];
30
+ }
31
+ return;
32
+ };
33
+ this._hoverAttract = () => {
34
+ const container = this.container, mousePos = container.interactivity.mouse.position, attractRadius = container.retina.attractModeDistance;
35
+ if (!attractRadius || attractRadius < 0 || !mousePos) {
36
+ return;
37
+ }
38
+ this._processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
39
+ };
40
+ this._processAttract = (position, attractRadius, area) => {
41
+ const container = this.container, attractOptions = container.actualOptions.interactivity.modes.attract;
42
+ if (!attractOptions) {
43
+ return;
44
+ }
45
+ const query = container.particles.quadTree.query(area, (p) => this.isEnabled(p));
46
+ for (const particle of query) {
47
+ const { dx, dy, distance } = getDistances(particle.position, position);
48
+ const velocity = attractOptions.speed * attractOptions.factor;
49
+ const attractFactor = clamp(getEasing(attractOptions.easing)(1 - distance / attractRadius) * velocity, 0, attractOptions.maxSpeed);
50
+ const normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * attractFactor, distance === 0 ? velocity : (dy / distance) * attractFactor);
51
+ particle.position.subFrom(normVec);
52
+ }
53
+ };
6
54
  this._engine = engine;
7
55
  if (!container.attract) {
8
56
  container.attract = { particles: [] };
@@ -26,12 +74,13 @@ export class Attractor extends ExternalInteractorBase {
26
74
  container.attract.particles = [];
27
75
  container.attract.finish = false;
28
76
  setTimeout(() => {
29
- if (!container.destroyed) {
30
- if (!container.attract) {
31
- container.attract = { particles: [] };
32
- }
33
- container.attract.clicking = false;
77
+ if (container.destroyed) {
78
+ return;
79
+ }
80
+ if (!container.attract) {
81
+ container.attract = { particles: [] };
34
82
  }
83
+ container.attract.clicking = false;
35
84
  }, attract.duration * 1000);
36
85
  };
37
86
  }
@@ -47,15 +96,14 @@ export class Attractor extends ExternalInteractorBase {
47
96
  async interact() {
48
97
  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;
49
98
  if (mouseMoveStatus && hoverEnabled && isInArray("attract", hoverMode)) {
50
- this.hoverAttract();
99
+ this._hoverAttract();
51
100
  }
52
101
  else if (clickEnabled && isInArray("attract", clickMode)) {
53
- this.clickAttract();
102
+ this._clickAttract();
54
103
  }
55
104
  }
56
105
  isEnabled(particle) {
57
- var _a;
58
- 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;
106
+ const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = (particle?.interactivity ?? options.interactivity).events;
59
107
  if ((!mouse.position || !events.onHover.enable) && (!mouse.clickPosition || !events.onClick.enable)) {
60
108
  return false;
61
109
  }
@@ -67,56 +115,9 @@ export class Attractor extends ExternalInteractorBase {
67
115
  options.attract = new Attract();
68
116
  }
69
117
  for (const source of sources) {
70
- options.attract.load(source === null || source === void 0 ? void 0 : source.attract);
118
+ options.attract.load(source?.attract);
71
119
  }
72
120
  }
73
121
  reset() {
74
122
  }
75
- clickAttract() {
76
- const container = this.container;
77
- if (!container.attract) {
78
- container.attract = { particles: [] };
79
- }
80
- if (!container.attract.finish) {
81
- if (!container.attract.count) {
82
- container.attract.count = 0;
83
- }
84
- container.attract.count++;
85
- if (container.attract.count === container.particles.count) {
86
- container.attract.finish = true;
87
- }
88
- }
89
- if (container.attract.clicking) {
90
- const mousePos = container.interactivity.mouse.clickPosition, attractRadius = container.retina.attractModeDistance;
91
- if (!attractRadius || attractRadius < 0 || !mousePos) {
92
- return;
93
- }
94
- this.processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
95
- }
96
- else if (container.attract.clicking === false) {
97
- container.attract.particles = [];
98
- }
99
- return;
100
- }
101
- hoverAttract() {
102
- const container = this.container, mousePos = container.interactivity.mouse.position, attractRadius = container.retina.attractModeDistance;
103
- if (!attractRadius || attractRadius < 0 || !mousePos) {
104
- return;
105
- }
106
- this.processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
107
- }
108
- processAttract(position, attractRadius, area) {
109
- const container = this.container, attractOptions = container.actualOptions.interactivity.modes.attract;
110
- if (!attractOptions) {
111
- return;
112
- }
113
- const query = container.particles.quadTree.query(area, (p) => this.isEnabled(p));
114
- for (const particle of query) {
115
- const { dx, dy, distance } = getDistances(particle.position, position);
116
- const velocity = attractOptions.speed * attractOptions.factor;
117
- const attractFactor = clamp(getEasing(attractOptions.easing)(1 - distance / attractRadius) * velocity, 0, attractOptions.maxSpeed);
118
- const normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * attractFactor, distance === 0 ? velocity : (dy / distance) * attractFactor);
119
- particle.position.subFrom(normVec);
120
- }
121
- }
122
123
  }
package/browser/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Attractor } from "./Attractor";
2
- export async function loadExternalAttractInteraction(engine) {
3
- await engine.addInteractor("externalAttract", (container) => new Attractor(engine, container));
2
+ export async function loadExternalAttractInteraction(engine, refresh = true) {
3
+ await engine.addInteractor("externalAttract", (container) => new Attractor(engine, container), refresh);
4
4
  }
5
5
  export * from "./Options/Classes/Attract";
6
6
  export * from "./Options/Interfaces/IAttract";
package/cjs/Attractor.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.Attractor = void 0;
13
4
  const engine_1 = require("@tsparticles/engine");
@@ -15,6 +6,54 @@ const Attract_1 = require("./Options/Classes/Attract");
15
6
  class Attractor extends engine_1.ExternalInteractorBase {
16
7
  constructor(engine, container) {
17
8
  super(container);
9
+ this._clickAttract = () => {
10
+ const container = this.container;
11
+ if (!container.attract) {
12
+ container.attract = { particles: [] };
13
+ }
14
+ const { attract } = container;
15
+ if (!attract.finish) {
16
+ if (!attract.count) {
17
+ attract.count = 0;
18
+ }
19
+ attract.count++;
20
+ if (attract.count === container.particles.count) {
21
+ attract.finish = true;
22
+ }
23
+ }
24
+ if (attract.clicking) {
25
+ const mousePos = container.interactivity.mouse.clickPosition, attractRadius = container.retina.attractModeDistance;
26
+ if (!attractRadius || attractRadius < 0 || !mousePos) {
27
+ return;
28
+ }
29
+ this._processAttract(mousePos, attractRadius, new engine_1.Circle(mousePos.x, mousePos.y, attractRadius));
30
+ }
31
+ else if (attract.clicking === false) {
32
+ attract.particles = [];
33
+ }
34
+ return;
35
+ };
36
+ this._hoverAttract = () => {
37
+ const container = this.container, mousePos = container.interactivity.mouse.position, attractRadius = container.retina.attractModeDistance;
38
+ if (!attractRadius || attractRadius < 0 || !mousePos) {
39
+ return;
40
+ }
41
+ this._processAttract(mousePos, attractRadius, new engine_1.Circle(mousePos.x, mousePos.y, attractRadius));
42
+ };
43
+ this._processAttract = (position, attractRadius, area) => {
44
+ const container = this.container, attractOptions = container.actualOptions.interactivity.modes.attract;
45
+ if (!attractOptions) {
46
+ return;
47
+ }
48
+ const query = container.particles.quadTree.query(area, (p) => this.isEnabled(p));
49
+ for (const particle of query) {
50
+ const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position);
51
+ const velocity = attractOptions.speed * attractOptions.factor;
52
+ const attractFactor = (0, engine_1.clamp)((0, engine_1.getEasing)(attractOptions.easing)(1 - distance / attractRadius) * velocity, 0, attractOptions.maxSpeed);
53
+ const normVec = engine_1.Vector.create(distance === 0 ? velocity : (dx / distance) * attractFactor, distance === 0 ? velocity : (dy / distance) * attractFactor);
54
+ particle.position.subFrom(normVec);
55
+ }
56
+ };
18
57
  this._engine = engine;
19
58
  if (!container.attract) {
20
59
  container.attract = { particles: [] };
@@ -38,12 +77,13 @@ class Attractor extends engine_1.ExternalInteractorBase {
38
77
  container.attract.particles = [];
39
78
  container.attract.finish = false;
40
79
  setTimeout(() => {
41
- if (!container.destroyed) {
42
- if (!container.attract) {
43
- container.attract = { particles: [] };
44
- }
45
- container.attract.clicking = false;
80
+ if (container.destroyed) {
81
+ return;
82
+ }
83
+ if (!container.attract) {
84
+ container.attract = { particles: [] };
46
85
  }
86
+ container.attract.clicking = false;
47
87
  }, attract.duration * 1000);
48
88
  };
49
89
  }
@@ -56,20 +96,17 @@ class Attractor extends engine_1.ExternalInteractorBase {
56
96
  }
57
97
  container.retina.attractModeDistance = attract.distance * container.retina.pixelRatio;
58
98
  }
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;
62
- if (mouseMoveStatus && hoverEnabled && (0, engine_1.isInArray)("attract", hoverMode)) {
63
- this.hoverAttract();
64
- }
65
- else if (clickEnabled && (0, engine_1.isInArray)("attract", clickMode)) {
66
- this.clickAttract();
67
- }
68
- });
99
+ async interact() {
100
+ 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;
101
+ if (mouseMoveStatus && hoverEnabled && (0, engine_1.isInArray)("attract", hoverMode)) {
102
+ this._hoverAttract();
103
+ }
104
+ else if (clickEnabled && (0, engine_1.isInArray)("attract", clickMode)) {
105
+ this._clickAttract();
106
+ }
69
107
  }
70
108
  isEnabled(particle) {
71
- var _a;
72
- 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;
109
+ const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = (particle?.interactivity ?? options.interactivity).events;
73
110
  if ((!mouse.position || !events.onHover.enable) && (!mouse.clickPosition || !events.onClick.enable)) {
74
111
  return false;
75
112
  }
@@ -81,57 +118,10 @@ class Attractor extends engine_1.ExternalInteractorBase {
81
118
  options.attract = new Attract_1.Attract();
82
119
  }
83
120
  for (const source of sources) {
84
- options.attract.load(source === null || source === void 0 ? void 0 : source.attract);
121
+ options.attract.load(source?.attract);
85
122
  }
86
123
  }
87
124
  reset() {
88
125
  }
89
- clickAttract() {
90
- const container = this.container;
91
- if (!container.attract) {
92
- container.attract = { particles: [] };
93
- }
94
- if (!container.attract.finish) {
95
- if (!container.attract.count) {
96
- container.attract.count = 0;
97
- }
98
- container.attract.count++;
99
- if (container.attract.count === container.particles.count) {
100
- container.attract.finish = true;
101
- }
102
- }
103
- if (container.attract.clicking) {
104
- const mousePos = container.interactivity.mouse.clickPosition, attractRadius = container.retina.attractModeDistance;
105
- if (!attractRadius || attractRadius < 0 || !mousePos) {
106
- return;
107
- }
108
- this.processAttract(mousePos, attractRadius, new engine_1.Circle(mousePos.x, mousePos.y, attractRadius));
109
- }
110
- else if (container.attract.clicking === false) {
111
- container.attract.particles = [];
112
- }
113
- return;
114
- }
115
- hoverAttract() {
116
- const container = this.container, mousePos = container.interactivity.mouse.position, attractRadius = container.retina.attractModeDistance;
117
- if (!attractRadius || attractRadius < 0 || !mousePos) {
118
- return;
119
- }
120
- this.processAttract(mousePos, attractRadius, new engine_1.Circle(mousePos.x, mousePos.y, attractRadius));
121
- }
122
- processAttract(position, attractRadius, area) {
123
- const container = this.container, attractOptions = container.actualOptions.interactivity.modes.attract;
124
- if (!attractOptions) {
125
- return;
126
- }
127
- const query = container.particles.quadTree.query(area, (p) => this.isEnabled(p));
128
- for (const particle of query) {
129
- const { dx, dy, distance } = (0, engine_1.getDistances)(particle.position, position);
130
- const velocity = attractOptions.speed * attractOptions.factor;
131
- const attractFactor = (0, engine_1.clamp)((0, engine_1.getEasing)(attractOptions.easing)(1 - distance / attractRadius) * velocity, 0, attractOptions.maxSpeed);
132
- const normVec = engine_1.Vector.create(distance === 0 ? velocity : (dx / distance) * attractFactor, distance === 0 ? velocity : (dy / distance) * attractFactor);
133
- particle.position.subFrom(normVec);
134
- }
135
- }
136
126
  }
137
127
  exports.Attractor = Attractor;
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.loadExternalAttractInteraction = void 0;
27
18
  const Attractor_1 = require("./Attractor");
28
- function loadExternalAttractInteraction(engine) {
29
- return __awaiter(this, void 0, void 0, function* () {
30
- yield engine.addInteractor("externalAttract", (container) => new Attractor_1.Attractor(engine, container));
31
- });
19
+ async function loadExternalAttractInteraction(engine, refresh = true) {
20
+ await engine.addInteractor("externalAttract", (container) => new Attractor_1.Attractor(engine, container), refresh);
32
21
  }
33
22
  exports.loadExternalAttractInteraction = loadExternalAttractInteraction;
34
23
  __exportStar(require("./Options/Classes/Attract"), exports);
package/esm/Attractor.js CHANGED
@@ -3,6 +3,54 @@ import { Attract } from "./Options/Classes/Attract";
3
3
  export class Attractor extends ExternalInteractorBase {
4
4
  constructor(engine, container) {
5
5
  super(container);
6
+ this._clickAttract = () => {
7
+ const container = this.container;
8
+ if (!container.attract) {
9
+ container.attract = { particles: [] };
10
+ }
11
+ const { attract } = container;
12
+ if (!attract.finish) {
13
+ if (!attract.count) {
14
+ attract.count = 0;
15
+ }
16
+ attract.count++;
17
+ if (attract.count === container.particles.count) {
18
+ attract.finish = true;
19
+ }
20
+ }
21
+ if (attract.clicking) {
22
+ const mousePos = container.interactivity.mouse.clickPosition, attractRadius = container.retina.attractModeDistance;
23
+ if (!attractRadius || attractRadius < 0 || !mousePos) {
24
+ return;
25
+ }
26
+ this._processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
27
+ }
28
+ else if (attract.clicking === false) {
29
+ attract.particles = [];
30
+ }
31
+ return;
32
+ };
33
+ this._hoverAttract = () => {
34
+ const container = this.container, mousePos = container.interactivity.mouse.position, attractRadius = container.retina.attractModeDistance;
35
+ if (!attractRadius || attractRadius < 0 || !mousePos) {
36
+ return;
37
+ }
38
+ this._processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
39
+ };
40
+ this._processAttract = (position, attractRadius, area) => {
41
+ const container = this.container, attractOptions = container.actualOptions.interactivity.modes.attract;
42
+ if (!attractOptions) {
43
+ return;
44
+ }
45
+ const query = container.particles.quadTree.query(area, (p) => this.isEnabled(p));
46
+ for (const particle of query) {
47
+ const { dx, dy, distance } = getDistances(particle.position, position);
48
+ const velocity = attractOptions.speed * attractOptions.factor;
49
+ const attractFactor = clamp(getEasing(attractOptions.easing)(1 - distance / attractRadius) * velocity, 0, attractOptions.maxSpeed);
50
+ const normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * attractFactor, distance === 0 ? velocity : (dy / distance) * attractFactor);
51
+ particle.position.subFrom(normVec);
52
+ }
53
+ };
6
54
  this._engine = engine;
7
55
  if (!container.attract) {
8
56
  container.attract = { particles: [] };
@@ -26,12 +74,13 @@ export class Attractor extends ExternalInteractorBase {
26
74
  container.attract.particles = [];
27
75
  container.attract.finish = false;
28
76
  setTimeout(() => {
29
- if (!container.destroyed) {
30
- if (!container.attract) {
31
- container.attract = { particles: [] };
32
- }
33
- container.attract.clicking = false;
77
+ if (container.destroyed) {
78
+ return;
79
+ }
80
+ if (!container.attract) {
81
+ container.attract = { particles: [] };
34
82
  }
83
+ container.attract.clicking = false;
35
84
  }, attract.duration * 1000);
36
85
  };
37
86
  }
@@ -47,15 +96,14 @@ export class Attractor extends ExternalInteractorBase {
47
96
  async interact() {
48
97
  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;
49
98
  if (mouseMoveStatus && hoverEnabled && isInArray("attract", hoverMode)) {
50
- this.hoverAttract();
99
+ this._hoverAttract();
51
100
  }
52
101
  else if (clickEnabled && isInArray("attract", clickMode)) {
53
- this.clickAttract();
102
+ this._clickAttract();
54
103
  }
55
104
  }
56
105
  isEnabled(particle) {
57
- var _a;
58
- 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;
106
+ const container = this.container, options = container.actualOptions, mouse = container.interactivity.mouse, events = (particle?.interactivity ?? options.interactivity).events;
59
107
  if ((!mouse.position || !events.onHover.enable) && (!mouse.clickPosition || !events.onClick.enable)) {
60
108
  return false;
61
109
  }
@@ -67,56 +115,9 @@ export class Attractor extends ExternalInteractorBase {
67
115
  options.attract = new Attract();
68
116
  }
69
117
  for (const source of sources) {
70
- options.attract.load(source === null || source === void 0 ? void 0 : source.attract);
118
+ options.attract.load(source?.attract);
71
119
  }
72
120
  }
73
121
  reset() {
74
122
  }
75
- clickAttract() {
76
- const container = this.container;
77
- if (!container.attract) {
78
- container.attract = { particles: [] };
79
- }
80
- if (!container.attract.finish) {
81
- if (!container.attract.count) {
82
- container.attract.count = 0;
83
- }
84
- container.attract.count++;
85
- if (container.attract.count === container.particles.count) {
86
- container.attract.finish = true;
87
- }
88
- }
89
- if (container.attract.clicking) {
90
- const mousePos = container.interactivity.mouse.clickPosition, attractRadius = container.retina.attractModeDistance;
91
- if (!attractRadius || attractRadius < 0 || !mousePos) {
92
- return;
93
- }
94
- this.processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
95
- }
96
- else if (container.attract.clicking === false) {
97
- container.attract.particles = [];
98
- }
99
- return;
100
- }
101
- hoverAttract() {
102
- const container = this.container, mousePos = container.interactivity.mouse.position, attractRadius = container.retina.attractModeDistance;
103
- if (!attractRadius || attractRadius < 0 || !mousePos) {
104
- return;
105
- }
106
- this.processAttract(mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius));
107
- }
108
- processAttract(position, attractRadius, area) {
109
- const container = this.container, attractOptions = container.actualOptions.interactivity.modes.attract;
110
- if (!attractOptions) {
111
- return;
112
- }
113
- const query = container.particles.quadTree.query(area, (p) => this.isEnabled(p));
114
- for (const particle of query) {
115
- const { dx, dy, distance } = getDistances(particle.position, position);
116
- const velocity = attractOptions.speed * attractOptions.factor;
117
- const attractFactor = clamp(getEasing(attractOptions.easing)(1 - distance / attractRadius) * velocity, 0, attractOptions.maxSpeed);
118
- const normVec = Vector.create(distance === 0 ? velocity : (dx / distance) * attractFactor, distance === 0 ? velocity : (dy / distance) * attractFactor);
119
- particle.position.subFrom(normVec);
120
- }
121
- }
122
123
  }
package/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Attractor } from "./Attractor";
2
- export async function loadExternalAttractInteraction(engine) {
3
- await engine.addInteractor("externalAttract", (container) => new Attractor(engine, container));
2
+ export async function loadExternalAttractInteraction(engine, refresh = true) {
3
+ await engine.addInteractor("externalAttract", (container) => new Attractor(engine, container), refresh);
4
4
  }
5
5
  export * from "./Options/Classes/Attract";
6
6
  export * from "./Options/Interfaces/IAttract";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsparticles/interaction-external-attract",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.0-beta.0",
4
4
  "description": "tsParticles attract external interaction",
5
5
  "homepage": "https://particles.js.org",
6
6
  "repository": {
@@ -73,10 +73,11 @@
73
73
  "unpkg": "tsparticles.interaction.external.attract.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
+ }