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