@tsparticles/interaction-particles-links 4.0.0-alpha.8 → 4.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/13.min.js +1 -0
- package/342.min.js +1 -0
- package/823.min.js +1 -0
- package/README.md +5 -0
- package/browser/CircleWarp.js +34 -18
- package/browser/LinkInstance.js +138 -131
- package/browser/Linker.js +47 -42
- package/browser/LinksPlugin.js +2 -1
- package/browser/Options/Classes/Links.js +12 -0
- package/browser/Options/Classes/LinksShadow.js +3 -0
- package/browser/Options/Classes/LinksTriangle.js +4 -0
- package/browser/Utils.js +2 -83
- package/browser/index.js +7 -4
- package/cjs/CircleWarp.js +34 -18
- package/cjs/LinkInstance.js +138 -131
- package/cjs/Linker.js +47 -42
- package/cjs/LinksPlugin.js +2 -1
- package/cjs/Options/Classes/Links.js +12 -0
- package/cjs/Options/Classes/LinksShadow.js +3 -0
- package/cjs/Options/Classes/LinksTriangle.js +4 -0
- package/cjs/Utils.js +2 -83
- package/cjs/index.js +7 -4
- package/dist_browser_LinkInstance_js.js +3 -3
- package/dist_browser_Linker_js.js +3 -3
- package/dist_browser_LinksPlugin_js.js +2 -2
- package/esm/CircleWarp.js +34 -18
- package/esm/LinkInstance.js +138 -131
- package/esm/Linker.js +47 -42
- package/esm/LinksPlugin.js +2 -1
- package/esm/Options/Classes/Links.js +12 -0
- package/esm/Options/Classes/LinksShadow.js +3 -0
- package/esm/Options/Classes/LinksTriangle.js +4 -0
- package/esm/Utils.js +2 -83
- package/esm/index.js +7 -4
- package/package.json +4 -3
- package/report.html +1 -1
- package/tsparticles.interaction.particles.links.js +45 -33
- package/tsparticles.interaction.particles.links.min.js +2 -2
- package/types/CircleWarp.d.ts +2 -2
- package/types/Interfaces.d.ts +4 -2
- package/types/LinkInstance.d.ts +6 -6
- package/types/Linker.d.ts +4 -1
- package/types/LinksPlugin.d.ts +1 -1
- package/types/Types.d.ts +11 -20
- package/types/Utils.d.ts +1 -5
- package/umd/CircleWarp.js +33 -17
- package/umd/LinkInstance.js +136 -129
- package/umd/Linker.js +46 -41
- package/umd/LinksPlugin.js +2 -1
- package/umd/Options/Classes/Links.js +12 -0
- package/umd/Options/Classes/LinksShadow.js +3 -0
- package/umd/Options/Classes/LinksTriangle.js +4 -0
- package/umd/Utils.js +1 -85
- package/umd/index.js +7 -4
- package/161.min.js +0 -2
- package/161.min.js.LICENSE.txt +0 -1
- package/29.min.js +0 -2
- package/29.min.js.LICENSE.txt +0 -1
- package/94.min.js +0 -2
- package/94.min.js.LICENSE.txt +0 -1
- package/tsparticles.interaction.particles.links.min.js.LICENSE.txt +0 -1
package/browser/Utils.js
CHANGED
|
@@ -1,87 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export function drawTriangle(context, p1, p2, p3) {
|
|
3
|
-
context.beginPath();
|
|
4
|
-
context.moveTo(p1.x, p1.y);
|
|
5
|
-
context.lineTo(p2.x, p2.y);
|
|
6
|
-
context.lineTo(p3.x, p3.y);
|
|
7
|
-
context.closePath();
|
|
8
|
-
}
|
|
9
|
-
export function drawLinkLine(params) {
|
|
10
|
-
let drawn = false;
|
|
11
|
-
const { begin, end, engine, maxDistance, context, canvasSize, width, colorLine, opacity, links, hdr } = params;
|
|
12
|
-
if (getDistance(begin, end) <= maxDistance) {
|
|
13
|
-
drawLine(context, begin, end);
|
|
14
|
-
drawn = true;
|
|
15
|
-
}
|
|
16
|
-
else if (links.warp) {
|
|
17
|
-
let pi1;
|
|
18
|
-
let pi2;
|
|
19
|
-
const endNE = {
|
|
20
|
-
x: end.x - canvasSize.width,
|
|
21
|
-
y: end.y,
|
|
22
|
-
};
|
|
23
|
-
const d1 = getDistances(begin, endNE);
|
|
24
|
-
if (d1.distance <= maxDistance) {
|
|
25
|
-
const yi = begin.y - (d1.dy / d1.dx) * begin.x;
|
|
26
|
-
pi1 = { x: 0, y: yi };
|
|
27
|
-
pi2 = { x: canvasSize.width, y: yi };
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
const endSW = {
|
|
31
|
-
x: end.x,
|
|
32
|
-
y: end.y - canvasSize.height,
|
|
33
|
-
};
|
|
34
|
-
const d2 = getDistances(begin, endSW);
|
|
35
|
-
if (d2.distance <= maxDistance) {
|
|
36
|
-
const yi = begin.y - (d2.dy / d2.dx) * begin.x;
|
|
37
|
-
const xi = -yi / (d2.dy / d2.dx);
|
|
38
|
-
pi1 = { x: xi, y: 0 };
|
|
39
|
-
pi2 = { x: xi, y: canvasSize.height };
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
const endSE = {
|
|
43
|
-
x: end.x - canvasSize.width,
|
|
44
|
-
y: end.y - canvasSize.height,
|
|
45
|
-
};
|
|
46
|
-
const d3 = getDistances(begin, endSE);
|
|
47
|
-
if (d3.distance <= maxDistance) {
|
|
48
|
-
const yi = begin.y - (d3.dy / d3.dx) * begin.x;
|
|
49
|
-
const xi = -yi / (d3.dy / d3.dx);
|
|
50
|
-
pi1 = { x: xi, y: yi };
|
|
51
|
-
pi2 = { x: pi1.x + canvasSize.width, y: pi1.y + canvasSize.height };
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (pi1 && pi2) {
|
|
56
|
-
drawLine(context, begin, pi1);
|
|
57
|
-
drawLine(context, end, pi2);
|
|
58
|
-
drawn = true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (!drawn) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
context.lineWidth = width;
|
|
65
|
-
context.strokeStyle = getStyleFromRgb(colorLine, hdr, opacity);
|
|
66
|
-
const { shadow } = links;
|
|
67
|
-
if (shadow.enable) {
|
|
68
|
-
const shadowColor = rangeColorToRgb(engine, shadow.color);
|
|
69
|
-
if (shadowColor) {
|
|
70
|
-
context.shadowBlur = shadow.blur;
|
|
71
|
-
context.shadowColor = getStyleFromRgb(shadowColor, hdr);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
context.stroke();
|
|
75
|
-
}
|
|
76
|
-
export function drawLinkTriangle(params) {
|
|
77
|
-
const { context, hdr, pos1, pos2, pos3, colorTriangle, opacityTriangle } = params;
|
|
78
|
-
drawTriangle(context, pos1, pos2, pos3);
|
|
79
|
-
context.fillStyle = getStyleFromRgb(colorTriangle, hdr, opacityTriangle);
|
|
80
|
-
context.fill();
|
|
81
|
-
}
|
|
1
|
+
import { getRandom } from "@tsparticles/engine";
|
|
82
2
|
export function getLinkKey(ids) {
|
|
83
|
-
ids.sort((a, b) => a - b);
|
|
84
|
-
return ids.join("_");
|
|
3
|
+
return [...ids].sort((a, b) => a - b).join("_");
|
|
85
4
|
}
|
|
86
5
|
export function setLinkFrequency(particles, dictionary) {
|
|
87
6
|
const key = getLinkKey(particles.map(t => t.id));
|
package/browser/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
export async function loadParticlesLinksInteraction(engine) {
|
|
2
|
-
engine.checkVersion("4.0.0-
|
|
2
|
+
engine.checkVersion("4.0.0-beta.0");
|
|
3
3
|
await engine.register(async (e) => {
|
|
4
|
-
const {
|
|
5
|
-
|
|
4
|
+
const [{ ensureInteractivityPluginLoaded }, { LinksPlugin },] = await Promise.all([
|
|
5
|
+
import("@tsparticles/plugin-interactivity"),
|
|
6
|
+
import("./LinksPlugin.js"),
|
|
7
|
+
]);
|
|
8
|
+
ensureInteractivityPluginLoaded(e);
|
|
6
9
|
e.addPlugin(new LinksPlugin(e));
|
|
7
10
|
e.addInteractor?.("particlesLinks", async (container) => {
|
|
8
11
|
const { Linker } = await import("./Linker.js");
|
|
9
|
-
return new Linker(container,
|
|
12
|
+
return new Linker(container, e);
|
|
10
13
|
});
|
|
11
14
|
});
|
|
12
15
|
}
|
package/cjs/CircleWarp.js
CHANGED
|
@@ -1,32 +1,48 @@
|
|
|
1
|
-
import { Circle, Rectangle
|
|
1
|
+
import { Circle, Rectangle } from "@tsparticles/engine";
|
|
2
2
|
export class CircleWarp extends Circle {
|
|
3
|
+
canvasSize;
|
|
3
4
|
constructor(x, y, radius, canvasSize) {
|
|
4
5
|
super(x, y, radius);
|
|
5
6
|
this.canvasSize = canvasSize;
|
|
6
|
-
this.canvasSize = { ...canvasSize };
|
|
7
7
|
}
|
|
8
8
|
contains(point) {
|
|
9
|
+
if (super.contains(point))
|
|
10
|
+
return true;
|
|
9
11
|
const { width, height } = this.canvasSize, { x, y } = point;
|
|
10
|
-
return (super.contains(
|
|
11
|
-
super.contains({ x: x
|
|
12
|
+
return (super.contains({ x: x - width, y }) ||
|
|
13
|
+
super.contains({ x: x + width, y }) ||
|
|
14
|
+
super.contains({ x, y: y - height }) ||
|
|
15
|
+
super.contains({ x, y: y + height }) ||
|
|
12
16
|
super.contains({ x: x - width, y: y - height }) ||
|
|
13
|
-
super.contains({ x, y: y
|
|
17
|
+
super.contains({ x: x + width, y: y + height }) ||
|
|
18
|
+
super.contains({ x: x - width, y: y + height }) ||
|
|
19
|
+
super.contains({ x: x + width, y: y - height }));
|
|
14
20
|
}
|
|
15
21
|
intersects(range) {
|
|
16
|
-
if (super.intersects(range))
|
|
22
|
+
if (super.intersects(range))
|
|
17
23
|
return true;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
x:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
const { width, height } = this.canvasSize, pos = range.position, shifts = [
|
|
25
|
+
{ x: -width, y: 0 },
|
|
26
|
+
{ x: width, y: 0 },
|
|
27
|
+
{ x: 0, y: -height },
|
|
28
|
+
{ x: 0, y: height },
|
|
29
|
+
{ x: -width, y: -height },
|
|
30
|
+
{ x: width, y: height },
|
|
31
|
+
{ x: -width, y: height },
|
|
32
|
+
{ x: width, y: -height },
|
|
33
|
+
];
|
|
34
|
+
for (const shift of shifts) {
|
|
35
|
+
const shiftedPos = { x: pos.x + shift.x, y: pos.y + shift.y };
|
|
36
|
+
let shiftedRange;
|
|
37
|
+
if (range instanceof Circle) {
|
|
38
|
+
shiftedRange = new Circle(shiftedPos.x, shiftedPos.y, range.radius);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const rect = range;
|
|
42
|
+
shiftedRange = new Rectangle(shiftedPos.x, shiftedPos.y, rect.size.width, rect.size.height);
|
|
43
|
+
}
|
|
44
|
+
if (super.intersects(shiftedRange))
|
|
45
|
+
return true;
|
|
30
46
|
}
|
|
31
47
|
return false;
|
|
32
48
|
}
|
package/cjs/LinkInstance.js
CHANGED
|
@@ -1,156 +1,163 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
const minOpacity = 0, minWidth = 0, minDistance = 0, maxFrequency = 1;
|
|
1
|
+
import { getLinkColor as engineGetLinkColor, getRandom, getRangeValue, getStyleFromRgb, half, originPoint, rangeColorToRgb, } from "@tsparticles/engine";
|
|
2
|
+
import { setLinkFrequency } from "./Utils.js";
|
|
3
|
+
const minOpacity = 0, minWidth = 0, minDistance = 0, maxFrequency = 1, defaultFrequency = 0;
|
|
4
4
|
export class LinkInstance {
|
|
5
|
+
_colorCache = new Map();
|
|
6
|
+
_container;
|
|
7
|
+
_engine;
|
|
8
|
+
_freqs;
|
|
5
9
|
constructor(container, engine) {
|
|
6
|
-
this.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
this._container = container;
|
|
11
|
+
this._engine = engine;
|
|
12
|
+
this._freqs = { links: new Map(), triangles: new Map() };
|
|
13
|
+
}
|
|
14
|
+
drawParticle(context, particle) {
|
|
15
|
+
const { links, options } = particle;
|
|
16
|
+
if (!links?.length || !options.links) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const linkOpts = options.links, width = particle.retina.linksWidth ?? minWidth, pos1 = particle.getPosition(), twinkle = particle.options["twinkle"]?.links, trianglesEnabled = linkOpts.triangles.enable, p1Destinations = trianglesEnabled ? new Set(links.map(l => l.destination.id)) : null, originalAlpha = context.globalAlpha;
|
|
20
|
+
let currentColorStyle = "", currentWidth = -1, currentAlpha = -1, pathOpen = false;
|
|
21
|
+
const flushLines = () => {
|
|
22
|
+
if (pathOpen) {
|
|
23
|
+
context.stroke();
|
|
24
|
+
pathOpen = false;
|
|
10
25
|
}
|
|
11
|
-
const container = this._container, 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(this._engine, 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 ?? minWidth, maxDistance = p1.retina.linksDistance ?? minDistance;
|
|
33
|
-
drawLinkLine({
|
|
34
|
-
context: ctx,
|
|
35
|
-
width,
|
|
36
|
-
begin: pos1,
|
|
37
|
-
end: pos2,
|
|
38
|
-
engine: this._engine,
|
|
39
|
-
maxDistance,
|
|
40
|
-
canvasSize: container.canvas.size,
|
|
41
|
-
links: p1LinksOptions,
|
|
42
|
-
colorLine,
|
|
43
|
-
opacity,
|
|
44
|
-
hdr: container.hdr,
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
26
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
27
|
+
for (const link of links) {
|
|
28
|
+
if (linkOpts.frequency < maxFrequency &&
|
|
29
|
+
this._getLinkFrequency(particle, link.destination) > linkOpts.frequency) {
|
|
30
|
+
continue;
|
|
52
31
|
}
|
|
53
|
-
const
|
|
54
|
-
if (!
|
|
55
|
-
|
|
32
|
+
const pos2 = link.destination.getPosition();
|
|
33
|
+
if (trianglesEnabled && !link.isWarped && p1Destinations) {
|
|
34
|
+
flushLines();
|
|
35
|
+
this._drawTriangles(options, particle, link, p1Destinations, pos1, pos2, context);
|
|
56
36
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return;
|
|
37
|
+
if (link.opacity <= minOpacity || width <= minWidth) {
|
|
38
|
+
continue;
|
|
60
39
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (!colorTriangle) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
drawLinkTriangle({
|
|
79
|
-
context: ctx,
|
|
80
|
-
pos1,
|
|
81
|
-
pos2,
|
|
82
|
-
pos3,
|
|
83
|
-
colorTriangle,
|
|
84
|
-
opacityTriangle,
|
|
85
|
-
hdr: container.hdr,
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
};
|
|
89
|
-
this._drawTriangles = (options, p1, link, p1Links) => {
|
|
90
|
-
const p2 = link.destination;
|
|
91
|
-
if (!(options.links?.triangles.enable && p2.options.links?.triangles.enable)) {
|
|
92
|
-
return;
|
|
40
|
+
if (!linkOpts.enable) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
let opacity = link.opacity, colorLine = link.color;
|
|
44
|
+
const twinkleRgb = twinkle?.enable && getRandom() < twinkle.frequency ? rangeColorToRgb(this._engine, twinkle.color) : undefined;
|
|
45
|
+
if (twinkle && twinkleRgb) {
|
|
46
|
+
colorLine = twinkleRgb;
|
|
47
|
+
opacity = getRangeValue(twinkle.opacity);
|
|
48
|
+
}
|
|
49
|
+
if (!colorLine) {
|
|
50
|
+
const linkColor = linkOpts.id !== undefined
|
|
51
|
+
? this._container.particles.linksColors.get(linkOpts.id)
|
|
52
|
+
: this._container.particles.linksColor;
|
|
53
|
+
colorLine = engineGetLinkColor(particle, link.destination, linkColor);
|
|
93
54
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return (p2.options.links &&
|
|
97
|
-
linkFreq <= p2.options.links.frequency &&
|
|
98
|
-
p1Links.findIndex(l => l.destination === t.destination) >= minCount);
|
|
99
|
-
});
|
|
100
|
-
if (!vertices?.length) {
|
|
101
|
-
return;
|
|
55
|
+
if (!colorLine) {
|
|
56
|
+
continue;
|
|
102
57
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
58
|
+
const colorStyle = this._getCachedStyle(colorLine);
|
|
59
|
+
if (colorStyle !== currentColorStyle || width !== currentWidth || opacity !== currentAlpha) {
|
|
60
|
+
flushLines();
|
|
61
|
+
context.strokeStyle = colorStyle;
|
|
62
|
+
context.lineWidth = width;
|
|
63
|
+
context.globalAlpha = opacity;
|
|
64
|
+
currentColorStyle = colorStyle;
|
|
65
|
+
currentWidth = width;
|
|
66
|
+
currentAlpha = opacity;
|
|
67
|
+
context.beginPath();
|
|
68
|
+
pathOpen = true;
|
|
69
|
+
}
|
|
70
|
+
if (link.isWarped) {
|
|
71
|
+
const canvasSize = this._container.canvas.size, dx = pos2.x - pos1.x, dy = pos2.y - pos1.y;
|
|
72
|
+
let sx = originPoint.x, sy = originPoint.y;
|
|
73
|
+
if (Math.abs(dx) > canvasSize.width * half) {
|
|
74
|
+
sx = dx > minDistance ? -canvasSize.width : canvasSize.width;
|
|
75
|
+
}
|
|
76
|
+
if (Math.abs(dy) > canvasSize.height * half) {
|
|
77
|
+
sy = dy > minDistance ? -canvasSize.height : canvasSize.height;
|
|
107
78
|
}
|
|
108
|
-
|
|
79
|
+
context.moveTo(pos1.x, pos1.y);
|
|
80
|
+
context.lineTo(pos2.x + sx, pos2.y + sy);
|
|
81
|
+
context.moveTo(pos1.x - sx, pos1.y - sy);
|
|
82
|
+
context.lineTo(pos2.x, pos2.y);
|
|
109
83
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
};
|
|
114
|
-
this._getTriangleFrequency = (p1, p2, p3) => {
|
|
115
|
-
return setLinkFrequency([p1, p2, p3], this._freqs.triangles);
|
|
116
|
-
};
|
|
117
|
-
this._container = container;
|
|
118
|
-
this._engine = engine;
|
|
119
|
-
this._freqs = {
|
|
120
|
-
links: new Map(),
|
|
121
|
-
triangles: new Map(),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
drawParticle(_context, particle) {
|
|
125
|
-
const { links, options } = particle;
|
|
126
|
-
if (!links?.length) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
const p1Links = links.filter(l => options.links &&
|
|
130
|
-
(options.links.frequency >= maxFrequency ||
|
|
131
|
-
this._getLinkFrequency(particle, l.destination) <= options.links.frequency));
|
|
132
|
-
for (const link of p1Links) {
|
|
133
|
-
this._drawTriangles(options, particle, link, p1Links);
|
|
134
|
-
if (link.opacity > minOpacity && (particle.retina.linksWidth ?? minWidth) > minWidth) {
|
|
135
|
-
this._drawLinkLine(particle, link);
|
|
84
|
+
else {
|
|
85
|
+
context.moveTo(pos1.x, pos1.y);
|
|
86
|
+
context.lineTo(pos2.x, pos2.y);
|
|
136
87
|
}
|
|
137
88
|
}
|
|
89
|
+
flushLines();
|
|
90
|
+
context.globalAlpha = originalAlpha;
|
|
138
91
|
}
|
|
139
|
-
|
|
140
|
-
this._freqs.links
|
|
141
|
-
this._freqs.triangles
|
|
142
|
-
|
|
92
|
+
init() {
|
|
93
|
+
this._freqs.links.clear();
|
|
94
|
+
this._freqs.triangles.clear();
|
|
95
|
+
this._colorCache.clear();
|
|
96
|
+
return Promise.resolve();
|
|
143
97
|
}
|
|
144
98
|
particleCreated(particle) {
|
|
145
99
|
particle.links = [];
|
|
146
100
|
if (!particle.options.links) {
|
|
147
101
|
return;
|
|
148
102
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
103
|
+
particle.linksDistance = particle.options.links.distance;
|
|
104
|
+
particle.linksWidth = particle.options.links.width;
|
|
105
|
+
const ratio = this._container.retina.pixelRatio;
|
|
106
|
+
particle.retina.linksDistance = particle.linksDistance * ratio;
|
|
107
|
+
particle.retina.linksWidth = particle.linksWidth * ratio;
|
|
152
108
|
}
|
|
153
109
|
particleDestroyed(particle) {
|
|
154
110
|
particle.links = [];
|
|
155
111
|
}
|
|
112
|
+
_drawTriangles(options, p1, link, p1Destinations, pos1, pos2, context) {
|
|
113
|
+
const p2 = link.destination, triangleOptions = options.links?.triangles;
|
|
114
|
+
if (!triangleOptions?.enable || !p2.options.links?.triangles.enable) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const p2Links = p2.links;
|
|
118
|
+
if (!p2Links?.length) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
for (const vertex of p2Links) {
|
|
122
|
+
if (vertex.isWarped ||
|
|
123
|
+
this._getLinkFrequency(p2, vertex.destination) > p2.options.links.frequency ||
|
|
124
|
+
!p1Destinations.has(vertex.destination.id)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const p3 = vertex.destination;
|
|
128
|
+
if (this._getTriangleFrequency(p1, p2, p3) > (options.links?.triangles.frequency ?? defaultFrequency)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const opacityTriangle = triangleOptions.opacity ?? (link.opacity + vertex.opacity) * half, colorTriangle = rangeColorToRgb(this._engine, triangleOptions.color) ?? link.color;
|
|
132
|
+
if (!colorTriangle || opacityTriangle <= minOpacity) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const pos3 = p3.getPosition();
|
|
136
|
+
context.save();
|
|
137
|
+
context.fillStyle = this._getCachedStyle(colorTriangle);
|
|
138
|
+
context.globalAlpha = opacityTriangle;
|
|
139
|
+
context.beginPath();
|
|
140
|
+
context.moveTo(pos1.x, pos1.y);
|
|
141
|
+
context.lineTo(pos2.x, pos2.y);
|
|
142
|
+
context.lineTo(pos3.x, pos3.y);
|
|
143
|
+
context.closePath();
|
|
144
|
+
context.fill();
|
|
145
|
+
context.restore();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
_getCachedStyle(rgb) {
|
|
149
|
+
const key = `${rgb.r},${rgb.g},${rgb.b}`;
|
|
150
|
+
let style = this._colorCache.get(key);
|
|
151
|
+
if (!style) {
|
|
152
|
+
style = getStyleFromRgb(rgb, this._container.hdr);
|
|
153
|
+
this._colorCache.set(key, style);
|
|
154
|
+
}
|
|
155
|
+
return style;
|
|
156
|
+
}
|
|
157
|
+
_getLinkFrequency(p1, p2) {
|
|
158
|
+
return setLinkFrequency([p1, p2], this._freqs.links);
|
|
159
|
+
}
|
|
160
|
+
_getTriangleFrequency(p1, p2, p3) {
|
|
161
|
+
return setLinkFrequency([p1, p2, p3], this._freqs.triangles);
|
|
162
|
+
}
|
|
156
163
|
}
|
package/cjs/Linker.js
CHANGED
|
@@ -1,46 +1,25 @@
|
|
|
1
|
-
import { Circle, getDistances, getLinkRandomColor, originPoint, } from "@tsparticles/engine";
|
|
1
|
+
import { Circle, getDistances, getLinkColor, getLinkRandomColor, originPoint, } from "@tsparticles/engine";
|
|
2
2
|
import { CircleWarp } from "./CircleWarp.js";
|
|
3
3
|
import { Links } from "./Options/Classes/Links.js";
|
|
4
4
|
import { ParticlesInteractorBase } from "@tsparticles/plugin-interactivity";
|
|
5
|
-
const
|
|
6
|
-
function
|
|
7
|
-
const { dx, dy
|
|
8
|
-
if (!warp || distance <= optDistance) {
|
|
9
|
-
return distance;
|
|
10
|
-
}
|
|
11
|
-
const absDiffs = {
|
|
12
|
-
x: Math.abs(dx),
|
|
13
|
-
y: Math.abs(dy),
|
|
14
|
-
}, warpDistances = {
|
|
5
|
+
const opacityOffset = 1, minDistance = 0;
|
|
6
|
+
function getWarpDistance(pos1, pos2, canvasSize) {
|
|
7
|
+
const { dx, dy } = getDistances(pos1, pos2), absDiffs = { x: Math.abs(dx), y: Math.abs(dy) }, warpDistances = {
|
|
15
8
|
x: Math.min(absDiffs.x, canvasSize.width - absDiffs.x),
|
|
16
9
|
y: Math.min(absDiffs.y, canvasSize.height - absDiffs.y),
|
|
17
10
|
};
|
|
18
|
-
return Math.
|
|
11
|
+
return Math.hypot(warpDistances.x, warpDistances.y);
|
|
19
12
|
}
|
|
20
13
|
export class Linker extends ParticlesInteractorBase {
|
|
14
|
+
_engine;
|
|
15
|
+
_maxDistance;
|
|
21
16
|
constructor(container, engine) {
|
|
22
17
|
super(container);
|
|
23
|
-
this._setColor = p1 => {
|
|
24
|
-
if (!p1.options.links) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const container = this.container, linksOptions = p1.options.links;
|
|
28
|
-
let linkColor = linksOptions.id === undefined
|
|
29
|
-
? container.particles.linksColor
|
|
30
|
-
: container.particles.linksColors.get(linksOptions.id);
|
|
31
|
-
if (linkColor) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const optColor = linksOptions.color;
|
|
35
|
-
linkColor = getLinkRandomColor(this._engine, optColor, linksOptions.blink, linksOptions.consent);
|
|
36
|
-
if (linksOptions.id === undefined) {
|
|
37
|
-
container.particles.linksColor = linkColor;
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
container.particles.linksColors.set(linksOptions.id, linkColor);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
18
|
this._engine = engine;
|
|
19
|
+
this._maxDistance = 0;
|
|
20
|
+
}
|
|
21
|
+
get maxDistance() {
|
|
22
|
+
return this._maxDistance;
|
|
44
23
|
}
|
|
45
24
|
clear() {
|
|
46
25
|
}
|
|
@@ -53,19 +32,14 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
53
32
|
return;
|
|
54
33
|
}
|
|
55
34
|
p1.links = [];
|
|
35
|
+
if (p1.linksDistance && p1.linksDistance > this._maxDistance) {
|
|
36
|
+
this._maxDistance = p1.linksDistance;
|
|
37
|
+
}
|
|
56
38
|
const pos1 = p1.getPosition(), container = this.container, canvasSize = container.canvas.size;
|
|
57
39
|
if (pos1.x < originPoint.x || pos1.y < originPoint.y || pos1.x > canvasSize.width || pos1.y > canvasSize.height) {
|
|
58
40
|
return;
|
|
59
41
|
}
|
|
60
|
-
const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance = p1.retina.linksDistance ?? minDistance, warp = linkOpt1.warp;
|
|
61
|
-
let range;
|
|
62
|
-
if (warp) {
|
|
63
|
-
range = new CircleWarp(pos1.x, pos1.y, optDistance, canvasSize);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
range = new Circle(pos1.x, pos1.y, optDistance);
|
|
67
|
-
}
|
|
68
|
-
const query = container.particles.quadTree.query(range);
|
|
42
|
+
const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance = p1.retina.linksDistance ?? minDistance, warp = linkOpt1.warp, range = warp ? new CircleWarp(pos1.x, pos1.y, optDistance, canvasSize) : new Circle(pos1.x, pos1.y, optDistance), query = container.particles.grid.query(range);
|
|
69
43
|
for (const p2 of query) {
|
|
70
44
|
const linkOpt2 = p2.options.links;
|
|
71
45
|
if (p1 === p2 ||
|
|
@@ -82,7 +56,7 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
82
56
|
if (pos2.x < originPoint.x || pos2.y < originPoint.y || pos2.x > canvasSize.width || pos2.y > canvasSize.height) {
|
|
83
57
|
continue;
|
|
84
58
|
}
|
|
85
|
-
const
|
|
59
|
+
const distDirect = getDistances(pos1, pos2).distance, distWarp = warp && linkOpt2.warp ? getWarpDistance(pos1, pos2, canvasSize) : distDirect, distance = Math.min(distDirect, distWarp);
|
|
86
60
|
if (distance > optDistance) {
|
|
87
61
|
continue;
|
|
88
62
|
}
|
|
@@ -91,6 +65,8 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
91
65
|
p1.links.push({
|
|
92
66
|
destination: p2,
|
|
93
67
|
opacity: opacityLine,
|
|
68
|
+
color: this._getLinkColor(p1, p2),
|
|
69
|
+
isWarped: distWarp < distDirect,
|
|
94
70
|
});
|
|
95
71
|
}
|
|
96
72
|
}
|
|
@@ -105,4 +81,33 @@ export class Linker extends ParticlesInteractorBase {
|
|
|
105
81
|
}
|
|
106
82
|
reset() {
|
|
107
83
|
}
|
|
84
|
+
_getLinkColor(p1, p2) {
|
|
85
|
+
const container = this.container, linksOptions = p1.options.links;
|
|
86
|
+
if (!linksOptions) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const linkColor = linksOptions.id !== undefined
|
|
90
|
+
? container.particles.linksColors.get(linksOptions.id)
|
|
91
|
+
: container.particles.linksColor;
|
|
92
|
+
return getLinkColor(p1, p2, linkColor);
|
|
93
|
+
}
|
|
94
|
+
_setColor(p1) {
|
|
95
|
+
if (!p1.options.links) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const container = this.container, linksOptions = p1.options.links;
|
|
99
|
+
let linkColor = linksOptions.id === undefined
|
|
100
|
+
? container.particles.linksColor
|
|
101
|
+
: container.particles.linksColors.get(linksOptions.id);
|
|
102
|
+
if (linkColor) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
linkColor = getLinkRandomColor(this._engine, linksOptions.color, linksOptions.blink, linksOptions.consent);
|
|
106
|
+
if (linksOptions.id === undefined) {
|
|
107
|
+
container.particles.linksColor = linkColor;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
container.particles.linksColors.set(linksOptions.id, linkColor);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
108
113
|
}
|
package/cjs/LinksPlugin.js
CHANGED
|
@@ -2,6 +2,18 @@ import { OptionsColor, isNull } from "@tsparticles/engine";
|
|
|
2
2
|
import { LinksShadow } from "./LinksShadow.js";
|
|
3
3
|
import { LinksTriangle } from "./LinksTriangle.js";
|
|
4
4
|
export class Links {
|
|
5
|
+
blink;
|
|
6
|
+
color;
|
|
7
|
+
consent;
|
|
8
|
+
distance;
|
|
9
|
+
enable;
|
|
10
|
+
frequency;
|
|
11
|
+
id;
|
|
12
|
+
opacity;
|
|
13
|
+
shadow;
|
|
14
|
+
triangles;
|
|
15
|
+
warp;
|
|
16
|
+
width;
|
|
5
17
|
constructor() {
|
|
6
18
|
this.blink = false;
|
|
7
19
|
this.color = new OptionsColor();
|