@tsparticles/interaction-external-repulse 3.0.0-alpha.0 → 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 Repulse Interaction
4
4
 
5
- [![jsDelivr](https://data.jsdelivr.com/v1/package/npm/tsparticles-interaction-external-repulse/badge)](https://www.jsdelivr.com/package/npm/tsparticles-interaction-external-repulse)
6
- [![npmjs](https://badge.fury.io/js/tsparticles-interaction-external-repulse.svg)](https://www.npmjs.com/package/tsparticles-interaction-external-repulse)
7
- [![npmjs](https://img.shields.io/npm/dt/tsparticles-interaction-external-repulse)](https://www.npmjs.com/package/tsparticles-interaction-external-repulse) [![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-repulse/badge)](https://www.jsdelivr.com/package/npm/@tsparticles/interaction-external-repulse)
6
+ [![npmjs](https://badge.fury.io/js/@tsparticles/interaction-external-repulse.svg)](https://www.npmjs.com/package/@tsparticles/interaction-external-repulse)
7
+ [![npmjs](https://img.shields.io/npm/dt/@tsparticles/interaction-external-repulse)](https://www.npmjs.com/package/@tsparticles/interaction-external-repulse) [![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 repulse effect around mouse or HTML
10
10
  elements.
@@ -27,14 +27,16 @@ loadExternalRepulseInteraction;
27
27
  Once the scripts are loaded you can set up `tsParticles` and the interaction plugin like this:
28
28
 
29
29
  ```javascript
30
- loadExternalRepulseInteraction(tsParticles);
31
-
32
- tsParticles.load({
33
- id: "tsparticles",
34
- options: {
35
- /* options */
36
- },
37
- });
30
+ (async () => {
31
+ await loadExternalRepulseInteraction(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-repulse
47
+ $ npm install @tsparticles/interaction-external-repulse
46
48
  ```
47
49
 
48
50
  or
49
51
 
50
52
  ```shell
51
- $ yarn add tsparticles-interaction-external-repulse
53
+ $ yarn add @tsparticles/interaction-external-repulse
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 { loadExternalRepulseInteraction } = require("tsparticles-interaction-external-repulse");
59
+ const { tsParticles } = require("@tsparticles/engine");
60
+ const { loadExternalRepulseInteraction } = require("@tsparticles/interaction-external-repulse");
59
61
 
60
- loadExternalRepulseInteraction(tsParticles);
62
+ (async () => {
63
+ await loadExternalRepulseInteraction(tsParticles);
64
+ })();
61
65
  ```
62
66
 
63
67
  or
64
68
 
65
69
  ```javascript
66
- import { tsParticles } from "tsparticles-engine";
67
- import { loadExternalRepulseInteraction } from "tsparticles-interaction-external-repulse";
70
+ import { tsParticles } from "@tsparticles/engine";
71
+ import { loadExternalRepulseInteraction } from "@tsparticles/interaction-external-repulse";
68
72
 
69
- loadExternalRepulseInteraction(tsParticles);
73
+ (async () => {
74
+ await loadExternalRepulseInteraction(tsParticles);
75
+ })();
70
76
  ```
@@ -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
  }
@@ -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/browser/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";
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Repulse = void 0;
4
+ const engine_1 = require("@tsparticles/engine");
4
5
  const RepulseBase_1 = require("./RepulseBase");
5
6
  const RepulseDiv_1 = require("./RepulseDiv");
6
- const engine_1 = require("@tsparticles/engine");
7
7
  class Repulse extends RepulseBase_1.RepulseBase {
8
8
  load(data) {
9
9
  super.load(data);
@@ -2,26 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RepulseDiv = void 0;
4
4
  const RepulseBase_1 = require("./RepulseBase");
5
- const engine_1 = require("@tsparticles/engine");
6
5
  class RepulseDiv extends RepulseBase_1.RepulseBase {
7
6
  constructor() {
8
7
  super();
9
8
  this.selectors = [];
10
9
  }
11
- get ids() {
12
- return (0, engine_1.executeOnSingleOrMultiple)(this.selectors, (t) => t.replace("#", ""));
13
- }
14
- set ids(value) {
15
- this.selectors = (0, engine_1.executeOnSingleOrMultiple)(value, (t) => `#${t}`);
16
- }
17
10
  load(data) {
18
11
  super.load(data);
19
12
  if (!data) {
20
13
  return;
21
14
  }
22
- if (data.ids !== undefined) {
23
- this.ids = data.ids;
24
- }
25
15
  if (data.selectors !== undefined) {
26
16
  this.selectors = data.selectors;
27
17
  }