@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/13.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(this.webpackChunk_tsparticles_interaction_particles_links=this.webpackChunk_tsparticles_interaction_particles_links||[]).push([[13],{13(n,i,t){t.r(i),t.d(i,{LinksPlugin:()=>e});class e{id="links";_engine;constructor(n){this._engine=n}async getPlugin(n){let{LinkInstance:i}=await t.e(823).then(t.bind(t,823));return new i(n,this._engine)}loadOptions(){}needsPlugin(){return!0}}}}]);
|
package/342.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(this.webpackChunk_tsparticles_interaction_particles_links=this.webpackChunk_tsparticles_interaction_particles_links||[]).push([[342],{342(i,t,n){n.d(t,{Linker:()=>a});var s=n(303);class e extends s.Circle{canvasSize;constructor(i,t,n,s){super(i,t,n),this.canvasSize=s}contains(i){if(super.contains(i))return!0;let{width:t,height:n}=this.canvasSize,{x:s,y:e}=i;return super.contains({x:s-t,y:e})||super.contains({x:s+t,y:e})||super.contains({x:s,y:e-n})||super.contains({x:s,y:e+n})||super.contains({x:s-t,y:e-n})||super.contains({x:s+t,y:e+n})||super.contains({x:s-t,y:e+n})||super.contains({x:s+t,y:e-n})}intersects(i){if(super.intersects(i))return!0;let{width:t,height:n}=this.canvasSize,e=i.position;for(let r of[{x:-t,y:0},{x:t,y:0},{x:0,y:-n},{x:0,y:n},{x:-t,y:-n},{x:t,y:n},{x:-t,y:n},{x:t,y:-n}]){let t,n={x:e.x+r.x,y:e.y+r.y};if(t=i instanceof s.Circle?new s.Circle(n.x,n.y,i.radius):new s.Rectangle(n.x,n.y,i.size.width,i.size.height),super.intersects(t))return!0}return!1}}var r=n(348),o=n(702);class a extends o.ParticlesInteractorBase{_engine;_maxDistance;constructor(i,t){super(i),this._engine=t,this._maxDistance=0}get maxDistance(){return this._maxDistance}clear(){}init(){this.container.particles.linksColor=void 0,this.container.particles.linksColors=new Map}interact(i){if(!i.options.links)return;i.links=[],i.linksDistance&&i.linksDistance>this._maxDistance&&(this._maxDistance=i.linksDistance);let t=i.getPosition(),n=this.container,r=n.canvas.size;if(t.x<s.originPoint.x||t.y<s.originPoint.y||t.x>r.width||t.y>r.height)return;let o=i.options.links,a=o.opacity,l=i.retina.linksDistance??0,c=o.warp,p=c?new e(t.x,t.y,l,r):new s.Circle(t.x,t.y,l);for(let e of n.particles.grid.query(p)){let n=e.options.links;if(i===e||!n?.enable||o.id!==n.id||e.spawning||e.destroyed||!e.links||i.links.some(i=>i.destination===e)||e.links.some(t=>t.destination===i))continue;let p=e.getPosition();if(p.x<s.originPoint.x||p.y<s.originPoint.y||p.x>r.width||p.y>r.height)continue;let h=(0,s.getDistances)(t,p).distance,x=c&&n.warp?function(i,t,n){let{dx:e,dy:r}=(0,s.getDistances)(i,t),o={x:Math.abs(e),y:Math.abs(r)},a={x:Math.min(o.x,n.width-o.x),y:Math.min(o.y,n.height-o.y)};return Math.hypot(a.x,a.y)}(t,p,r):h,k=Math.min(h,x);if(k>l)continue;let u=(1-k/l)*a;this._setColor(i),i.links.push({destination:e,opacity:u,color:this._getLinkColor(i,e),isWarped:x<h})}}isEnabled(i){return!!i.options.links?.enable}loadParticlesOptions(i,...t){for(let n of(i.links??=new r.q,t))i.links.load(n?.links)}reset(){}_getLinkColor(i,t){let n=this.container,e=i.options.links;if(!e)return;let r=void 0!==e.id?n.particles.linksColors.get(e.id):n.particles.linksColor;return(0,s.getLinkColor)(i,t,r)}_setColor(i){if(!i.options.links)return;let t=this.container,n=i.options.links,e=void 0===n.id?t.particles.linksColor:t.particles.linksColors.get(n.id);e||(e=(0,s.getLinkRandomColor)(this._engine,n.color,n.blink,n.consent),void 0===n.id?t.particles.linksColor=e:t.particles.linksColors.set(n.id,e))}}}}]);
|
package/823.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(this.webpackChunk_tsparticles_interaction_particles_links=this.webpackChunk_tsparticles_interaction_particles_links||[]).push([[823],{823(e,i,t){t.d(i,{LinkInstance:()=>s});var n=t(303);function l(e,i){let t=[...e.map(e=>e.id)].sort((e,i)=>e-i).join("_"),l=i.get(t);return void 0===l&&(l=(0,n.getRandom)(),i.set(t,l)),l}class s{_colorCache=new Map;_container;_engine;_freqs;constructor(e,i){this._container=e,this._engine=i,this._freqs={links:new Map,triangles:new Map}}drawParticle(e,i){let{links:t,options:l}=i;if(!t?.length||!l.links)return;let s=l.links,o=i.retina.linksWidth??0,a=i.getPosition(),r=i.options.twinkle?.links,c=s.triangles.enable,h=c?new Set(t.map(e=>e.destination.id)):null,g=e.globalAlpha,d="",_=-1,k=-1,p=!1,y=()=>{p&&(e.stroke(),p=!1)};for(let g of t){if(s.frequency<1&&this._getLinkFrequency(i,g.destination)>s.frequency)continue;let t=g.destination.getPosition();if(c&&!g.isWarped&&h&&(y(),this._drawTriangles(l,i,g,h,a,t,e)),g.opacity<=0||o<=0||!s.enable)continue;let f=g.opacity,u=g.color,b=r?.enable&&(0,n.getRandom)()<r.frequency?(0,n.rangeColorToRgb)(this._engine,r.color):void 0;if(r&&b&&(u=b,f=(0,n.getRangeValue)(r.opacity)),!u){let e=void 0!==s.id?this._container.particles.linksColors.get(s.id):this._container.particles.linksColor;u=(0,n.getLinkColor)(i,g.destination,e)}if(!u)continue;let q=this._getCachedStyle(u);if((q!==d||o!==_||f!==k)&&(y(),e.strokeStyle=q,e.lineWidth=o,e.globalAlpha=f,d=q,_=o,k=f,e.beginPath(),p=!0),g.isWarped){let i=this._container.canvas.size,l=t.x-a.x,s=t.y-a.y,o=n.originPoint.x,r=n.originPoint.y;Math.abs(l)>i.width*n.half&&(o=l>0?-i.width:i.width),Math.abs(s)>i.height*n.half&&(r=s>0?-i.height:i.height),e.moveTo(a.x,a.y),e.lineTo(t.x+o,t.y+r),e.moveTo(a.x-o,a.y-r),e.lineTo(t.x,t.y)}else e.moveTo(a.x,a.y),e.lineTo(t.x,t.y)}y(),e.globalAlpha=g}init(){return this._freqs.links.clear(),this._freqs.triangles.clear(),this._colorCache.clear(),Promise.resolve()}particleCreated(e){if(e.links=[],!e.options.links)return;e.linksDistance=e.options.links.distance,e.linksWidth=e.options.links.width;let i=this._container.retina.pixelRatio;e.retina.linksDistance=e.linksDistance*i,e.retina.linksWidth=e.linksWidth*i}particleDestroyed(e){e.links=[]}_drawTriangles(e,i,t,l,s,o,a){let r=t.destination,c=e.links?.triangles;if(!c?.enable||!r.options.links?.triangles.enable)return;let h=r.links;if(h?.length)for(let g of h){if(g.isWarped||this._getLinkFrequency(r,g.destination)>r.options.links.frequency||!l.has(g.destination.id))continue;let h=g.destination;if(this._getTriangleFrequency(i,r,h)>(e.links?.triangles.frequency??0))continue;let d=c.opacity??(t.opacity+g.opacity)*n.half,_=(0,n.rangeColorToRgb)(this._engine,c.color)??t.color;if(!_||d<=0)continue;let k=h.getPosition();a.save(),a.fillStyle=this._getCachedStyle(_),a.globalAlpha=d,a.beginPath(),a.moveTo(s.x,s.y),a.lineTo(o.x,o.y),a.lineTo(k.x,k.y),a.closePath(),a.fill(),a.restore()}}_getCachedStyle(e){let i=`${e.r},${e.g},${e.b}`,t=this._colorCache.get(i);return t||(t=(0,n.getStyleFromRgb)(e,this._container.hdr),this._colorCache.set(i,t)),t}_getLinkFrequency(e,i){return l([e,i],this._freqs.links)}_getTriangleFrequency(e,i,t){return l([e,i,t],this._freqs.triangles)}}}}]);
|
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@ Once the scripts are loaded you can set up `tsParticles` and the interaction plu
|
|
|
27
27
|
|
|
28
28
|
```javascript
|
|
29
29
|
(async () => {
|
|
30
|
+
await loadInteractivityPlugin(tsParticles);
|
|
30
31
|
await loadParticlesLinksInteraction(tsParticles);
|
|
31
32
|
|
|
32
33
|
await tsParticles.load({
|
|
@@ -56,9 +57,11 @@ Then you need to import it in the app, like this:
|
|
|
56
57
|
|
|
57
58
|
```javascript
|
|
58
59
|
const { tsParticles } = require("@tsparticles/engine");
|
|
60
|
+
const { loadInteractivityPlugin } = require("@tsparticles/plugin-interactivity");
|
|
59
61
|
const { loadParticlesLinksInteraction } = require("@tsparticles/interaction-particles-links");
|
|
60
62
|
|
|
61
63
|
(async () => {
|
|
64
|
+
await loadInteractivityPlugin(tsParticles);
|
|
62
65
|
await loadParticlesLinksInteraction(tsParticles);
|
|
63
66
|
})();
|
|
64
67
|
```
|
|
@@ -67,9 +70,11 @@ or
|
|
|
67
70
|
|
|
68
71
|
```javascript
|
|
69
72
|
import { tsParticles } from "@tsparticles/engine";
|
|
73
|
+
import { loadInteractivityPlugin } from "@tsparticles/plugin-interactivity";
|
|
70
74
|
import { loadParticlesLinksInteraction } from "@tsparticles/interaction-particles-links";
|
|
71
75
|
|
|
72
76
|
(async () => {
|
|
77
|
+
await loadInteractivityPlugin(tsParticles);
|
|
73
78
|
await loadParticlesLinksInteraction(tsParticles);
|
|
74
79
|
})();
|
|
75
80
|
```
|
package/browser/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/browser/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/browser/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/browser/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();
|