@tsparticles/interaction-particles-links 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 +25 -19
- package/browser/CircleWarp.js +7 -23
- package/browser/LinkInstance.js +121 -114
- package/browser/Linker.js +37 -54
- package/browser/Options/Classes/Links.js +1 -1
- package/browser/Utils.js +24 -8
- package/browser/index.js +5 -5
- package/browser/interaction.js +2 -2
- package/browser/plugin.js +2 -2
- package/cjs/CircleWarp.js +7 -23
- package/cjs/LinkInstance.js +123 -127
- package/cjs/Linker.js +66 -94
- package/cjs/Options/Classes/Links.js +1 -1
- package/cjs/Utils.js +26 -8
- package/cjs/index.js +3 -14
- package/cjs/interaction.js +4 -15
- package/cjs/plugin.js +5 -16
- package/esm/CircleWarp.js +7 -23
- package/esm/LinkInstance.js +121 -114
- package/esm/Linker.js +37 -54
- package/esm/Options/Classes/Links.js +1 -1
- package/esm/Utils.js +24 -8
- package/esm/index.js +5 -5
- package/esm/interaction.js +2 -2
- package/esm/plugin.js +2 -2
- package/package.json +6 -5
- package/report.html +4 -4
- package/tsparticles.interaction.particles.links.js +244 -204
- package/tsparticles.interaction.particles.links.min.js +1 -1
- package/tsparticles.interaction.particles.links.min.js.LICENSE.txt +1 -8
- package/types/CircleWarp.d.ts +1 -2
- package/types/Interfaces.d.ts +22 -0
- package/types/LinkInstance.d.ts +7 -8
- package/types/Linker.d.ts +3 -7
- package/types/Options/Classes/Links.d.ts +1 -2
- package/types/Options/Classes/LinksShadow.d.ts +1 -2
- package/types/Options/Classes/LinksTriangle.d.ts +1 -2
- package/types/Types.d.ts +47 -0
- package/types/Utils.d.ts +5 -4
- package/types/index.d.ts +1 -1
- package/types/interaction.d.ts +1 -1
- package/types/plugin.d.ts +1 -1
- package/umd/CircleWarp.js +7 -23
- package/umd/LinkInstance.js +121 -114
- package/umd/Linker.js +36 -53
- package/umd/Options/Classes/Links.js +2 -2
- package/umd/Utils.js +26 -8
- package/umd/index.js +3 -3
- package/umd/interaction.js +4 -4
- package/umd/plugin.js +4 -4
- package/browser/Options/Interfaces/IParticlesLinkOptions.js +0 -1
- package/cjs/LinkParticle.js +0 -2
- package/cjs/Options/Classes/ParticlesLinkOptions.js +0 -2
- package/cjs/Options/Interfaces/IParticlesLinkOptions.js +0 -2
- package/esm/ILink.js +0 -1
- package/esm/LinkContainer.js +0 -1
- package/esm/LinkParticle.js +0 -1
- package/esm/Options/Classes/ParticlesLinkOptions.js +0 -1
- package/esm/Options/Interfaces/IParticlesLinkOptions.js +0 -1
- package/types/ILink.d.ts +0 -9
- package/types/LinkContainer.d.ts +0 -7
- package/types/LinkParticle.d.ts +0 -11
- package/types/Options/Classes/ParticlesLinkOptions.d.ts +0 -5
- package/types/Options/Interfaces/IParticlesLinkOptions.d.ts +0 -7
- package/umd/LinkParticle.js +0 -12
- package/umd/Options/Classes/ParticlesLinkOptions.js +0 -12
- package/umd/Options/Interfaces/IParticlesLinkOptions.js +0 -12
- /package/browser/{ILink.js → Interfaces.js} +0 -0
- /package/browser/{LinkContainer.js → Types.js} +0 -0
- /package/cjs/{ILink.js → Interfaces.js} +0 -0
- /package/cjs/{LinkContainer.js → Types.js} +0 -0
- /package/{browser/LinkParticle.js → esm/Interfaces.js} +0 -0
- /package/{browser/Options/Classes/ParticlesLinkOptions.js → esm/Types.js} +0 -0
- /package/umd/{ILink.js → Interfaces.js} +0 -0
- /package/umd/{LinkContainer.js → Types.js} +0 -0
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# tsParticles Particles Links Interaction
|
|
4
4
|
|
|
5
|
-
[](https://www.jsdelivr.com/package/npm/@tsparticles/interaction-particles-links)
|
|
6
|
+
[](https://www.npmjs.com/package/@tsparticles/interaction-particles-links)
|
|
7
|
+
[](https://www.npmjs.com/package/@tsparticles/interaction-particles-links) [](https://github.com/sponsors/matteobruni)
|
|
8
8
|
|
|
9
9
|
[tsParticles](https://github.com/matteobruni/tsparticles) interaction plugin for links effect between particles.
|
|
10
10
|
|
|
@@ -26,14 +26,16 @@ loadParticlesLinksInteraction;
|
|
|
26
26
|
Once the scripts are loaded you can set up `tsParticles` and the interaction plugin like this:
|
|
27
27
|
|
|
28
28
|
```javascript
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
29
|
+
(async () => {
|
|
30
|
+
await loadParticlesLinksInteraction(tsParticles);
|
|
31
|
+
|
|
32
|
+
await tsParticles.load({
|
|
33
|
+
id: "tsparticles",
|
|
34
|
+
options: {
|
|
35
|
+
/* options */
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
})();
|
|
37
39
|
```
|
|
38
40
|
|
|
39
41
|
### ESM / CommonJS
|
|
@@ -41,29 +43,33 @@ tsParticles.load({
|
|
|
41
43
|
This package is compatible also with ES or CommonJS modules, firstly this needs to be installed, like this:
|
|
42
44
|
|
|
43
45
|
```shell
|
|
44
|
-
$ npm install tsparticles
|
|
46
|
+
$ npm install @tsparticles/interaction-particles-links
|
|
45
47
|
```
|
|
46
48
|
|
|
47
49
|
or
|
|
48
50
|
|
|
49
51
|
```shell
|
|
50
|
-
$ yarn add tsparticles
|
|
52
|
+
$ yarn add @tsparticles/interaction-particles-links
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
Then you need to import it in the app, like this:
|
|
54
56
|
|
|
55
57
|
```javascript
|
|
56
|
-
const { tsParticles } = require("tsparticles
|
|
57
|
-
const { loadParticlesLinksInteraction } = require("tsparticles
|
|
58
|
+
const { tsParticles } = require("@tsparticles/engine");
|
|
59
|
+
const { loadParticlesLinksInteraction } = require("@tsparticles/interaction-particles-links");
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
(async () => {
|
|
62
|
+
await loadParticlesLinksInteraction(tsParticles);
|
|
63
|
+
})();
|
|
60
64
|
```
|
|
61
65
|
|
|
62
66
|
or
|
|
63
67
|
|
|
64
68
|
```javascript
|
|
65
|
-
import { tsParticles } from "tsparticles
|
|
66
|
-
import { loadParticlesLinksInteraction } from "tsparticles
|
|
69
|
+
import { tsParticles } from "@tsparticles/engine";
|
|
70
|
+
import { loadParticlesLinksInteraction } from "@tsparticles/interaction-particles-links";
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
(async () => {
|
|
73
|
+
await loadParticlesLinksInteraction(tsParticles);
|
|
74
|
+
})();
|
|
69
75
|
```
|
package/browser/CircleWarp.js
CHANGED
|
@@ -3,31 +3,15 @@ export class CircleWarp extends Circle {
|
|
|
3
3
|
constructor(x, y, radius, canvasSize) {
|
|
4
4
|
super(x, y, radius);
|
|
5
5
|
this.canvasSize = canvasSize;
|
|
6
|
-
this.canvasSize =
|
|
6
|
+
this.canvasSize = { ...canvasSize };
|
|
7
7
|
}
|
|
8
8
|
contains(point) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
x:
|
|
14
|
-
y:
|
|
15
|
-
};
|
|
16
|
-
if (super.contains(posNE)) {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
const posSE = {
|
|
20
|
-
x: point.x - this.canvasSize.width,
|
|
21
|
-
y: point.y - this.canvasSize.height,
|
|
22
|
-
};
|
|
23
|
-
if (super.contains(posSE)) {
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
const posSW = {
|
|
27
|
-
x: point.x,
|
|
28
|
-
y: point.y - this.canvasSize.height,
|
|
29
|
-
};
|
|
30
|
-
return super.contains(posSW);
|
|
9
|
+
const { width, height } = this.canvasSize;
|
|
10
|
+
const { x, y } = point;
|
|
11
|
+
return (super.contains(point) ||
|
|
12
|
+
super.contains({ x: x - width, y }) ||
|
|
13
|
+
super.contains({ x: x - width, y: y - height }) ||
|
|
14
|
+
super.contains({ x, y: y - height }));
|
|
31
15
|
}
|
|
32
16
|
intersects(range) {
|
|
33
17
|
if (super.intersects(range)) {
|
package/browser/LinkInstance.js
CHANGED
|
@@ -1,37 +1,133 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
function getLinkKey(ids) {
|
|
4
|
-
ids.sort((a, b) => a - b);
|
|
5
|
-
return ids.join("_");
|
|
6
|
-
}
|
|
7
|
-
function setLinkFrequency(particles, dictionary) {
|
|
8
|
-
const key = getLinkKey(particles.map((t) => t.id));
|
|
9
|
-
let res = dictionary.get(key);
|
|
10
|
-
if (res === undefined) {
|
|
11
|
-
res = getRandom();
|
|
12
|
-
dictionary.set(key, res);
|
|
13
|
-
}
|
|
14
|
-
return res;
|
|
15
|
-
}
|
|
1
|
+
import { getDistance, getLinkColor, getRandom, getRangeValue, rangeColorToRgb, } from "@tsparticles/engine";
|
|
2
|
+
import { drawLinkLine, drawLinkTriangle, setLinkFrequency } from "./Utils";
|
|
16
3
|
export class LinkInstance {
|
|
17
4
|
constructor(container) {
|
|
18
5
|
this.container = container;
|
|
6
|
+
this._drawLinkLine = (p1, link) => {
|
|
7
|
+
const p1LinksOptions = p1.options.links;
|
|
8
|
+
if (!p1LinksOptions?.enable) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const container = this.container, options = container.actualOptions, p2 = link.destination, pos1 = p1.getPosition(), pos2 = p2.getPosition();
|
|
12
|
+
let opacity = link.opacity;
|
|
13
|
+
container.canvas.draw((ctx) => {
|
|
14
|
+
let colorLine;
|
|
15
|
+
const twinkle = p1.options.twinkle?.lines;
|
|
16
|
+
if (twinkle?.enable) {
|
|
17
|
+
const twinkleFreq = twinkle.frequency, twinkleRgb = rangeColorToRgb(twinkle.color), twinkling = getRandom() < twinkleFreq;
|
|
18
|
+
if (twinkling && twinkleRgb) {
|
|
19
|
+
colorLine = twinkleRgb;
|
|
20
|
+
opacity = getRangeValue(twinkle.opacity);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (!colorLine) {
|
|
24
|
+
const linkColor = p1LinksOptions.id !== undefined
|
|
25
|
+
? container.particles.linksColors.get(p1LinksOptions.id)
|
|
26
|
+
: container.particles.linksColor;
|
|
27
|
+
colorLine = getLinkColor(p1, p2, linkColor);
|
|
28
|
+
}
|
|
29
|
+
if (!colorLine) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const width = p1.retina.linksWidth ?? 0, maxDistance = p1.retina.linksDistance ?? 0, { backgroundMask } = options;
|
|
33
|
+
drawLinkLine({
|
|
34
|
+
context: ctx,
|
|
35
|
+
width,
|
|
36
|
+
begin: pos1,
|
|
37
|
+
end: pos2,
|
|
38
|
+
maxDistance,
|
|
39
|
+
canvasSize: container.canvas.size,
|
|
40
|
+
links: p1LinksOptions,
|
|
41
|
+
backgroundMask: backgroundMask,
|
|
42
|
+
colorLine,
|
|
43
|
+
opacity,
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
this._drawLinkTriangle = (p1, link1, link2) => {
|
|
48
|
+
const linksOptions = p1.options.links;
|
|
49
|
+
if (!linksOptions?.enable) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const triangleOptions = linksOptions.triangles;
|
|
53
|
+
if (!triangleOptions.enable) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const container = this.container, options = container.actualOptions, p2 = link1.destination, p3 = link2.destination, opacityTriangle = triangleOptions.opacity ?? (link1.opacity + link2.opacity) / 2;
|
|
57
|
+
if (opacityTriangle <= 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
container.canvas.draw((ctx) => {
|
|
61
|
+
const pos1 = p1.getPosition(), pos2 = p2.getPosition(), pos3 = p3.getPosition(), linksDistance = p1.retina.linksDistance ?? 0;
|
|
62
|
+
if (getDistance(pos1, pos2) > linksDistance ||
|
|
63
|
+
getDistance(pos3, pos2) > linksDistance ||
|
|
64
|
+
getDistance(pos3, pos1) > linksDistance) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let colorTriangle = rangeColorToRgb(triangleOptions.color);
|
|
68
|
+
if (!colorTriangle) {
|
|
69
|
+
const linkColor = linksOptions.id !== undefined
|
|
70
|
+
? container.particles.linksColors.get(linksOptions.id)
|
|
71
|
+
: container.particles.linksColor;
|
|
72
|
+
colorTriangle = getLinkColor(p1, p2, linkColor);
|
|
73
|
+
}
|
|
74
|
+
if (!colorTriangle) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
drawLinkTriangle({
|
|
78
|
+
context: ctx,
|
|
79
|
+
pos1,
|
|
80
|
+
pos2,
|
|
81
|
+
pos3,
|
|
82
|
+
backgroundMask: options.backgroundMask,
|
|
83
|
+
colorTriangle,
|
|
84
|
+
opacityTriangle,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
this._drawTriangles = (options, p1, link, p1Links) => {
|
|
89
|
+
const p2 = link.destination;
|
|
90
|
+
if (!(options.links?.triangles.enable && p2.options.links?.triangles.enable)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const vertices = p2.links?.filter((t) => {
|
|
94
|
+
const linkFreq = this._getLinkFrequency(p2, t.destination);
|
|
95
|
+
return (p2.options.links &&
|
|
96
|
+
linkFreq <= p2.options.links.frequency &&
|
|
97
|
+
p1Links.findIndex((l) => l.destination === t.destination) >= 0);
|
|
98
|
+
});
|
|
99
|
+
if (!vertices?.length) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
for (const vertex of vertices) {
|
|
103
|
+
const p3 = vertex.destination, triangleFreq = this._getTriangleFrequency(p1, p2, p3);
|
|
104
|
+
if (triangleFreq > options.links.triangles.frequency) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
this._drawLinkTriangle(p1, link, vertex);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
this._getLinkFrequency = (p1, p2) => {
|
|
111
|
+
return setLinkFrequency([p1, p2], this._freqs.links);
|
|
112
|
+
};
|
|
113
|
+
this._getTriangleFrequency = (p1, p2, p3) => {
|
|
114
|
+
return setLinkFrequency([p1, p2, p3], this._freqs.triangles);
|
|
115
|
+
};
|
|
19
116
|
this._freqs = {
|
|
20
117
|
links: new Map(),
|
|
21
118
|
triangles: new Map(),
|
|
22
119
|
};
|
|
23
120
|
}
|
|
24
121
|
drawParticle(context, particle) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!particle.links || particle.links.length <= 0) {
|
|
122
|
+
const { links, options } = particle;
|
|
123
|
+
if (!links || links.length <= 0) {
|
|
28
124
|
return;
|
|
29
125
|
}
|
|
30
|
-
const p1Links =
|
|
126
|
+
const p1Links = links.filter((l) => options.links && this._getLinkFrequency(particle, l.destination) <= options.links.frequency);
|
|
31
127
|
for (const link of p1Links) {
|
|
32
|
-
this.
|
|
33
|
-
if (link.opacity > 0 && (
|
|
34
|
-
this.
|
|
128
|
+
this._drawTriangles(options, particle, link, p1Links);
|
|
129
|
+
if (link.opacity > 0 && (particle.retina.linksWidth ?? 0) > 0) {
|
|
130
|
+
this._drawLinkLine(particle, link);
|
|
35
131
|
}
|
|
36
132
|
}
|
|
37
133
|
}
|
|
@@ -44,100 +140,11 @@ export class LinkInstance {
|
|
|
44
140
|
if (!particle.options.links) {
|
|
45
141
|
return;
|
|
46
142
|
}
|
|
47
|
-
const ratio = this.container.retina.pixelRatio;
|
|
48
|
-
|
|
49
|
-
|
|
143
|
+
const ratio = this.container.retina.pixelRatio, { retina } = particle, { distance, width } = particle.options.links;
|
|
144
|
+
retina.linksDistance = distance * ratio;
|
|
145
|
+
retina.linksWidth = width * ratio;
|
|
50
146
|
}
|
|
51
147
|
particleDestroyed(particle) {
|
|
52
148
|
particle.links = [];
|
|
53
149
|
}
|
|
54
|
-
drawLinkLine(p1, link) {
|
|
55
|
-
const container = this.container, options = container.actualOptions, p2 = link.destination, pos1 = p1.getPosition(), pos2 = p2.getPosition();
|
|
56
|
-
let opacity = link.opacity;
|
|
57
|
-
container.canvas.draw((ctx) => {
|
|
58
|
-
var _a, _b, _c;
|
|
59
|
-
if (!p1.options.links) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
let colorLine;
|
|
63
|
-
const twinkle = (_a = p1.options.twinkle) === null || _a === void 0 ? void 0 : _a.lines;
|
|
64
|
-
if (twinkle === null || twinkle === void 0 ? void 0 : twinkle.enable) {
|
|
65
|
-
const twinkleFreq = twinkle.frequency, twinkleRgb = rangeColorToRgb(twinkle.color), twinkling = getRandom() < twinkleFreq;
|
|
66
|
-
if (twinkling && twinkleRgb) {
|
|
67
|
-
colorLine = twinkleRgb;
|
|
68
|
-
opacity = getRangeValue(twinkle.opacity);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (!colorLine) {
|
|
72
|
-
const linksOptions = p1.options.links, linkColor = (linksOptions === null || linksOptions === void 0 ? void 0 : linksOptions.id) !== undefined
|
|
73
|
-
? container.particles.linksColors.get(linksOptions.id)
|
|
74
|
-
: container.particles.linksColor;
|
|
75
|
-
colorLine = getLinkColor(p1, p2, linkColor);
|
|
76
|
-
}
|
|
77
|
-
if (!colorLine) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const width = (_b = p1.retina.linksWidth) !== null && _b !== void 0 ? _b : 0, maxDistance = (_c = p1.retina.linksDistance) !== null && _c !== void 0 ? _c : 0;
|
|
81
|
-
drawLinkLine(ctx, width, pos1, pos2, maxDistance, container.canvas.size, p1.options.links.warp, options.backgroundMask.enable, options.backgroundMask.composite, colorLine, opacity, p1.options.links.shadow);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
drawLinkTriangle(p1, link1, link2) {
|
|
85
|
-
var _a;
|
|
86
|
-
if (!p1.options.links) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const container = this.container, options = container.actualOptions, p2 = link1.destination, p3 = link2.destination, triangleOptions = p1.options.links.triangles, opacityTriangle = (_a = triangleOptions.opacity) !== null && _a !== void 0 ? _a : (link1.opacity + link2.opacity) / 2;
|
|
90
|
-
if (opacityTriangle <= 0) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
container.canvas.draw((ctx) => {
|
|
94
|
-
var _a;
|
|
95
|
-
const pos1 = p1.getPosition(), pos2 = p2.getPosition(), pos3 = p3.getPosition(), linksDistance = (_a = p1.retina.linksDistance) !== null && _a !== void 0 ? _a : 0;
|
|
96
|
-
if (getDistance(pos1, pos2) > linksDistance ||
|
|
97
|
-
getDistance(pos3, pos2) > linksDistance ||
|
|
98
|
-
getDistance(pos3, pos1) > linksDistance) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
let colorTriangle = rangeColorToRgb(triangleOptions.color);
|
|
102
|
-
if (!colorTriangle) {
|
|
103
|
-
const linksOptions = p1.options.links, linkColor = (linksOptions === null || linksOptions === void 0 ? void 0 : linksOptions.id) !== undefined
|
|
104
|
-
? container.particles.linksColors.get(linksOptions.id)
|
|
105
|
-
: container.particles.linksColor;
|
|
106
|
-
colorTriangle = getLinkColor(p1, p2, linkColor);
|
|
107
|
-
}
|
|
108
|
-
if (!colorTriangle) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
drawLinkTriangle(ctx, pos1, pos2, pos3, options.backgroundMask.enable, options.backgroundMask.composite, colorTriangle, opacityTriangle);
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
drawTriangles(options, p1, link, p1Links) {
|
|
115
|
-
var _a, _b, _c;
|
|
116
|
-
const p2 = link.destination;
|
|
117
|
-
if (!(((_a = options.links) === null || _a === void 0 ? void 0 : _a.triangles.enable) && ((_b = p2.options.links) === null || _b === void 0 ? void 0 : _b.triangles.enable))) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const vertices = (_c = p2.links) === null || _c === void 0 ? void 0 : _c.filter((t) => {
|
|
121
|
-
const linkFreq = this.getLinkFrequency(p2, t.destination);
|
|
122
|
-
return (p2.options.links &&
|
|
123
|
-
linkFreq <= p2.options.links.frequency &&
|
|
124
|
-
p1Links.findIndex((l) => l.destination === t.destination) >= 0);
|
|
125
|
-
});
|
|
126
|
-
if (!(vertices === null || vertices === void 0 ? void 0 : vertices.length)) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
for (const vertex of vertices) {
|
|
130
|
-
const p3 = vertex.destination, triangleFreq = this.getTriangleFrequency(p1, p2, p3);
|
|
131
|
-
if (triangleFreq > options.links.triangles.frequency) {
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
this.drawLinkTriangle(p1, link, vertex);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
getLinkFrequency(p1, p2) {
|
|
138
|
-
return setLinkFrequency([p1, p2], this._freqs.links);
|
|
139
|
-
}
|
|
140
|
-
getTriangleFrequency(p1, p2, p3) {
|
|
141
|
-
return setLinkFrequency([p1, p2, p3], this._freqs.triangles);
|
|
142
|
-
}
|
|
143
150
|
}
|
package/browser/Linker.js
CHANGED
|
@@ -1,37 +1,43 @@
|
|
|
1
|
-
import { Circle, ParticlesInteractorBase,
|
|
1
|
+
import { Circle, ParticlesInteractorBase, getDistances, getLinkRandomColor, } from "@tsparticles/engine";
|
|
2
2
|
import { CircleWarp } from "./CircleWarp";
|
|
3
3
|
import { Links } from "./Options/Classes/Links";
|
|
4
4
|
function getLinkDistance(pos1, pos2, optDistance, canvasSize, warp) {
|
|
5
|
-
|
|
5
|
+
const { dx, dy, distance } = getDistances(pos1, pos2);
|
|
6
6
|
if (!warp || distance <= optDistance) {
|
|
7
7
|
return distance;
|
|
8
8
|
}
|
|
9
|
-
const
|
|
10
|
-
x:
|
|
11
|
-
y:
|
|
9
|
+
const absDiffs = {
|
|
10
|
+
x: Math.abs(dx),
|
|
11
|
+
y: Math.abs(dy),
|
|
12
|
+
}, warpDistances = {
|
|
13
|
+
x: Math.min(absDiffs.x, canvasSize.width - absDiffs.x),
|
|
14
|
+
y: Math.min(absDiffs.y, canvasSize.height - absDiffs.y),
|
|
12
15
|
};
|
|
13
|
-
|
|
14
|
-
if (distance <= optDistance) {
|
|
15
|
-
return distance;
|
|
16
|
-
}
|
|
17
|
-
const pos2SE = {
|
|
18
|
-
x: pos2.x - canvasSize.width,
|
|
19
|
-
y: pos2.y - canvasSize.height,
|
|
20
|
-
};
|
|
21
|
-
distance = getDistance(pos1, pos2SE);
|
|
22
|
-
if (distance <= optDistance) {
|
|
23
|
-
return distance;
|
|
24
|
-
}
|
|
25
|
-
const pos2SW = {
|
|
26
|
-
x: pos2.x,
|
|
27
|
-
y: pos2.y - canvasSize.height,
|
|
28
|
-
};
|
|
29
|
-
distance = getDistance(pos1, pos2SW);
|
|
30
|
-
return distance;
|
|
16
|
+
return Math.sqrt(warpDistances.x ** 2 + warpDistances.y ** 2);
|
|
31
17
|
}
|
|
32
18
|
export class Linker extends ParticlesInteractorBase {
|
|
33
19
|
constructor(container) {
|
|
34
20
|
super(container);
|
|
21
|
+
this._setColor = (p1) => {
|
|
22
|
+
if (!p1.options.links) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const container = this.linkContainer, linksOptions = p1.options.links;
|
|
26
|
+
let linkColor = linksOptions.id === undefined
|
|
27
|
+
? container.particles.linksColor
|
|
28
|
+
: container.particles.linksColors.get(linksOptions.id);
|
|
29
|
+
if (linkColor) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const optColor = linksOptions.color;
|
|
33
|
+
linkColor = getLinkRandomColor(optColor, linksOptions.blink, linksOptions.consent);
|
|
34
|
+
if (linksOptions.id === undefined) {
|
|
35
|
+
container.particles.linksColor = linkColor;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
container.particles.linksColors.set(linksOptions.id, linkColor);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
35
41
|
this.linkContainer = container;
|
|
36
42
|
}
|
|
37
43
|
clear() {
|
|
@@ -41,7 +47,6 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
41
47
|
this.linkContainer.particles.linksColors = new Map();
|
|
42
48
|
}
|
|
43
49
|
async interact(p1) {
|
|
44
|
-
var _a;
|
|
45
50
|
if (!p1.options.links) {
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
@@ -50,19 +55,19 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
50
55
|
if (pos1.x < 0 || pos1.y < 0 || pos1.x > canvasSize.width || pos1.y > canvasSize.height) {
|
|
51
56
|
return;
|
|
52
57
|
}
|
|
53
|
-
const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance =
|
|
58
|
+
const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance = p1.retina.linksDistance ?? 0, warp = linkOpt1.warp, range = warp
|
|
54
59
|
? new CircleWarp(pos1.x, pos1.y, optDistance, canvasSize)
|
|
55
60
|
: new Circle(pos1.x, pos1.y, optDistance), query = container.particles.quadTree.query(range);
|
|
56
61
|
for (const p2 of query) {
|
|
57
62
|
const linkOpt2 = p2.options.links;
|
|
58
63
|
if (p1 === p2 ||
|
|
59
|
-
!
|
|
64
|
+
!linkOpt2?.enable ||
|
|
60
65
|
linkOpt1.id !== linkOpt2.id ||
|
|
61
66
|
p2.spawning ||
|
|
62
67
|
p2.destroyed ||
|
|
63
68
|
!p2.links ||
|
|
64
|
-
p1.links.
|
|
65
|
-
p2.links.
|
|
69
|
+
p1.links.some((t) => t.destination === p2) ||
|
|
70
|
+
p2.links.some((t) => t.destination === p1)) {
|
|
66
71
|
continue;
|
|
67
72
|
}
|
|
68
73
|
const pos2 = p2.getPosition();
|
|
@@ -71,10 +76,10 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
71
76
|
}
|
|
72
77
|
const distance = getLinkDistance(pos1, pos2, optDistance, canvasSize, warp && linkOpt2.warp);
|
|
73
78
|
if (distance > optDistance) {
|
|
74
|
-
|
|
79
|
+
continue;
|
|
75
80
|
}
|
|
76
81
|
const opacityLine = (1 - distance / optDistance) * optOpacity;
|
|
77
|
-
this.
|
|
82
|
+
this._setColor(p1);
|
|
78
83
|
p1.links.push({
|
|
79
84
|
destination: p2,
|
|
80
85
|
opacity: opacityLine,
|
|
@@ -82,38 +87,16 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
89
|
isEnabled(particle) {
|
|
85
|
-
|
|
86
|
-
return !!((_a = particle.options.links) === null || _a === void 0 ? void 0 : _a.enable);
|
|
90
|
+
return !!particle.options.links?.enable;
|
|
87
91
|
}
|
|
88
92
|
loadParticlesOptions(options, ...sources) {
|
|
89
|
-
var _a, _b;
|
|
90
93
|
if (!options.links) {
|
|
91
94
|
options.links = new Links();
|
|
92
95
|
}
|
|
93
96
|
for (const source of sources) {
|
|
94
|
-
options.links.load(
|
|
97
|
+
options.links.load(source?.links ?? source?.lineLinked ?? source?.line_linked);
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
reset() {
|
|
98
101
|
}
|
|
99
|
-
setColor(p1) {
|
|
100
|
-
if (!p1.options.links) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
const container = this.linkContainer, linksOptions = p1.options.links;
|
|
104
|
-
let linkColor = linksOptions.id === undefined
|
|
105
|
-
? container.particles.linksColor
|
|
106
|
-
: container.particles.linksColors.get(linksOptions.id);
|
|
107
|
-
if (linkColor) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const optColor = linksOptions.color;
|
|
111
|
-
linkColor = getLinkRandomColor(optColor, linksOptions.blink, linksOptions.consent);
|
|
112
|
-
if (linksOptions.id === undefined) {
|
|
113
|
-
container.particles.linksColor = linkColor;
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
container.particles.linksColors.set(linksOptions.id, linkColor);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
102
|
}
|
package/browser/Utils.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { drawLine, drawTriangle, getDistance, getDistances, getStyleFromRgb, rangeColorToRgb, } from "@tsparticles/engine";
|
|
2
|
-
export function drawLinkLine(
|
|
1
|
+
import { drawLine, drawTriangle, getDistance, getDistances, getRandom, getStyleFromRgb, rangeColorToRgb, } from "@tsparticles/engine";
|
|
2
|
+
export function drawLinkLine(params) {
|
|
3
3
|
let drawn = false;
|
|
4
|
+
const { begin, end, maxDistance, context, canvasSize, width, backgroundMask, colorLine, opacity, links } = params;
|
|
4
5
|
if (getDistance(begin, end) <= maxDistance) {
|
|
5
6
|
drawLine(context, begin, end);
|
|
6
7
|
drawn = true;
|
|
7
8
|
}
|
|
8
|
-
else if (warp) {
|
|
9
|
+
else if (links.warp) {
|
|
9
10
|
let pi1;
|
|
10
11
|
let pi2;
|
|
11
12
|
const endNE = {
|
|
@@ -54,10 +55,11 @@ export function drawLinkLine(context, width, begin, end, maxDistance, canvasSize
|
|
|
54
55
|
return;
|
|
55
56
|
}
|
|
56
57
|
context.lineWidth = width;
|
|
57
|
-
if (backgroundMask) {
|
|
58
|
-
context.globalCompositeOperation = composite;
|
|
58
|
+
if (backgroundMask.enable) {
|
|
59
|
+
context.globalCompositeOperation = backgroundMask.composite;
|
|
59
60
|
}
|
|
60
61
|
context.strokeStyle = getStyleFromRgb(colorLine, opacity);
|
|
62
|
+
const { shadow } = links;
|
|
61
63
|
if (shadow.enable) {
|
|
62
64
|
const shadowColor = rangeColorToRgb(shadow.color);
|
|
63
65
|
if (shadowColor) {
|
|
@@ -67,11 +69,25 @@ export function drawLinkLine(context, width, begin, end, maxDistance, canvasSize
|
|
|
67
69
|
}
|
|
68
70
|
context.stroke();
|
|
69
71
|
}
|
|
70
|
-
export function drawLinkTriangle(
|
|
72
|
+
export function drawLinkTriangle(params) {
|
|
73
|
+
const { context, pos1, pos2, pos3, backgroundMask, colorTriangle, opacityTriangle } = params;
|
|
71
74
|
drawTriangle(context, pos1, pos2, pos3);
|
|
72
|
-
if (backgroundMask) {
|
|
73
|
-
context.globalCompositeOperation = composite;
|
|
75
|
+
if (backgroundMask.enable) {
|
|
76
|
+
context.globalCompositeOperation = backgroundMask.composite;
|
|
74
77
|
}
|
|
75
78
|
context.fillStyle = getStyleFromRgb(colorTriangle, opacityTriangle);
|
|
76
79
|
context.fill();
|
|
77
80
|
}
|
|
81
|
+
export function getLinkKey(ids) {
|
|
82
|
+
ids.sort((a, b) => a - b);
|
|
83
|
+
return ids.join("_");
|
|
84
|
+
}
|
|
85
|
+
export function setLinkFrequency(particles, dictionary) {
|
|
86
|
+
const key = getLinkKey(particles.map((t) => t.id));
|
|
87
|
+
let res = dictionary.get(key);
|
|
88
|
+
if (res === undefined) {
|
|
89
|
+
res = getRandom();
|
|
90
|
+
dictionary.set(key, res);
|
|
91
|
+
}
|
|
92
|
+
return res;
|
|
93
|
+
}
|
package/browser/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export async function loadParticlesLinksInteraction(engine) {
|
|
4
|
-
await
|
|
5
|
-
await
|
|
1
|
+
import { loadLinksInteraction } from "./interaction";
|
|
2
|
+
import { loadLinksPlugin } from "./plugin";
|
|
3
|
+
export async function loadParticlesLinksInteraction(engine, refresh = true) {
|
|
4
|
+
await loadLinksInteraction(engine, refresh);
|
|
5
|
+
await loadLinksPlugin(engine, refresh);
|
|
6
6
|
}
|
|
7
7
|
export * from "./Options/Classes/Links";
|
|
8
8
|
export * from "./Options/Classes/LinksShadow";
|
package/browser/interaction.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Linker } from "./Linker";
|
|
2
|
-
export async function
|
|
3
|
-
await engine.addInteractor("particlesLinks", (container) => new Linker(container));
|
|
2
|
+
export async function loadLinksInteraction(engine, refresh = true) {
|
|
3
|
+
await engine.addInteractor("particlesLinks", (container) => new Linker(container), refresh);
|
|
4
4
|
}
|
package/browser/plugin.js
CHANGED
|
@@ -12,7 +12,7 @@ class LinksPlugin {
|
|
|
12
12
|
return true;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
export async function
|
|
15
|
+
export async function loadLinksPlugin(engine, refresh = true) {
|
|
16
16
|
const plugin = new LinksPlugin();
|
|
17
|
-
await engine.addPlugin(plugin);
|
|
17
|
+
await engine.addPlugin(plugin, refresh);
|
|
18
18
|
}
|
package/cjs/CircleWarp.js
CHANGED
|
@@ -6,31 +6,15 @@ class CircleWarp extends engine_1.Circle {
|
|
|
6
6
|
constructor(x, y, radius, canvasSize) {
|
|
7
7
|
super(x, y, radius);
|
|
8
8
|
this.canvasSize = canvasSize;
|
|
9
|
-
this.canvasSize =
|
|
9
|
+
this.canvasSize = { ...canvasSize };
|
|
10
10
|
}
|
|
11
11
|
contains(point) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
x:
|
|
17
|
-
y:
|
|
18
|
-
};
|
|
19
|
-
if (super.contains(posNE)) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
const posSE = {
|
|
23
|
-
x: point.x - this.canvasSize.width,
|
|
24
|
-
y: point.y - this.canvasSize.height,
|
|
25
|
-
};
|
|
26
|
-
if (super.contains(posSE)) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
const posSW = {
|
|
30
|
-
x: point.x,
|
|
31
|
-
y: point.y - this.canvasSize.height,
|
|
32
|
-
};
|
|
33
|
-
return super.contains(posSW);
|
|
12
|
+
const { width, height } = this.canvasSize;
|
|
13
|
+
const { x, y } = point;
|
|
14
|
+
return (super.contains(point) ||
|
|
15
|
+
super.contains({ x: x - width, y }) ||
|
|
16
|
+
super.contains({ x: x - width, y: y - height }) ||
|
|
17
|
+
super.contains({ x, y: y - height }));
|
|
34
18
|
}
|
|
35
19
|
intersects(range) {
|
|
36
20
|
if (super.intersects(range)) {
|