canvasparticles-js 4.5.4 → 4.5.5
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/dist/index.cjs +42 -45
- package/dist/index.mjs +42 -45
- package/dist/index.umd.js +1 -1
- package/package.json +4 -4
- package/src/index.ts +35 -31
package/dist/index.cjs
CHANGED
|
@@ -21,25 +21,21 @@ function parseNumericOption(name, value, defaultValue, clamp) {
|
|
|
21
21
|
// https://github.com/Khoeckman/canvasparticles-js/blob/main/LICENSE
|
|
22
22
|
const TWO_PI = 2 * Math.PI;
|
|
23
23
|
/** Extremely fast, simple 32‑bit PRNG */
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
31
|
-
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
32
|
-
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
33
|
-
},
|
|
24
|
+
function mulberry32(seed) {
|
|
25
|
+
return function () {
|
|
26
|
+
let t = (seed += 0x6d2b79f5);
|
|
27
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
28
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
29
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
34
30
|
};
|
|
35
31
|
}
|
|
36
32
|
// Mulberry32 is x4 faster than Math.random()
|
|
37
33
|
// Benchmark: https://jsbm.dev/muLCWR9RJCbmy
|
|
38
34
|
// Spectral test: /demo/mulberry32.html
|
|
39
|
-
const prng =
|
|
35
|
+
const prng = mulberry32((Math.random() * 4294967296) | 0);
|
|
40
36
|
class CanvasParticles {
|
|
41
37
|
/** Version of the library, injected via Rollup replace plugin. */
|
|
42
|
-
static version = "4.5.
|
|
38
|
+
static version = "4.5.5";
|
|
43
39
|
static MAX_DT = 1000 / 30; // milliseconds between updates @ 30 FPS
|
|
44
40
|
static BASE_DT = 1000 / 60; // milliseconds between updates @ 60 FPS
|
|
45
41
|
/** Defines mouse interaction types with the particles */
|
|
@@ -497,6 +493,7 @@ class CanvasParticles {
|
|
|
497
493
|
const halfMaxDistSq = (maxDist / 2) ** 2;
|
|
498
494
|
const invCellSize = 1 / maxDist;
|
|
499
495
|
const stride = Math.ceil(this.width * invCellSize);
|
|
496
|
+
const rows = Math.ceil(this.height * invCellSize);
|
|
500
497
|
const drawAll = maxDist >= Math.min(this.canvas.width, this.canvas.height);
|
|
501
498
|
const maxWorkPerParticle = maxDistSq * this.option.particles.maxWork;
|
|
502
499
|
const alpha = this.color.alpha;
|
|
@@ -571,22 +568,22 @@ class CanvasParticles {
|
|
|
571
568
|
let cell;
|
|
572
569
|
if ((cell = grid.get(key + 1)))
|
|
573
570
|
renderConnectionsToCell(cell, pa); // (+1, 0)
|
|
574
|
-
if (
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
571
|
+
if (allowWork) {
|
|
572
|
+
if ((cell = grid.get(key + stride)))
|
|
573
|
+
renderConnectionsToCell(cell, pa); // (0, +1)
|
|
574
|
+
if (allowWork) {
|
|
575
|
+
if ((cell = grid.get(key + stride + 1)))
|
|
576
|
+
renderConnectionsToCell(cell, pa); // (+1, +1)
|
|
577
|
+
if (allowWork) {
|
|
578
|
+
if ((cell = grid.get(key + stride - 1)))
|
|
579
|
+
renderConnectionsToCell(cell, pa); // (-1, +1)
|
|
580
|
+
if (allowWork) {
|
|
581
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
582
|
+
renderConnectionsToOwnCell(cell || [], a, pa);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
590
587
|
// Next iteration
|
|
591
588
|
if (++a >= len)
|
|
592
589
|
break;
|
|
@@ -599,22 +596,22 @@ class CanvasParticles {
|
|
|
599
596
|
key = cellX + Math.imul(cellY, stride);
|
|
600
597
|
if ((cell = grid.get(key + stride + 1)))
|
|
601
598
|
renderConnectionsToCell(cell, pa); // (+1, +1)
|
|
602
|
-
if (
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
599
|
+
if (allowWork) {
|
|
600
|
+
if ((cell = grid.get(key + stride - 1)))
|
|
601
|
+
renderConnectionsToCell(cell, pa); // (-1, +1)
|
|
602
|
+
if (allowWork) {
|
|
603
|
+
if ((cell = grid.get(key + 1)))
|
|
604
|
+
renderConnectionsToCell(cell, pa); // (+1, 0)
|
|
605
|
+
if (allowWork) {
|
|
606
|
+
if ((cell = grid.get(key + stride)))
|
|
607
|
+
renderConnectionsToCell(cell, pa); // (0, +1)
|
|
608
|
+
if (allowWork) {
|
|
609
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
610
|
+
renderConnectionsToOwnCell(cell || [], a, pa);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
618
615
|
// Next iteration
|
|
619
616
|
if (++a >= len)
|
|
620
617
|
break;
|
|
@@ -633,7 +630,7 @@ class CanvasParticles {
|
|
|
633
630
|
renderConnectionsToCell(cell, pa); // (+1, 0)
|
|
634
631
|
if (!allowWork)
|
|
635
632
|
continue;
|
|
636
|
-
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
|
|
633
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
637
634
|
renderConnectionsToOwnCell(cell || [], a, pa);
|
|
638
635
|
if (!allowWork)
|
|
639
636
|
continue;
|
package/dist/index.mjs
CHANGED
|
@@ -19,25 +19,21 @@ function parseNumericOption(name, value, defaultValue, clamp) {
|
|
|
19
19
|
// https://github.com/Khoeckman/canvasparticles-js/blob/main/LICENSE
|
|
20
20
|
const TWO_PI = 2 * Math.PI;
|
|
21
21
|
/** Extremely fast, simple 32‑bit PRNG */
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
29
|
-
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
30
|
-
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
31
|
-
},
|
|
22
|
+
function mulberry32(seed) {
|
|
23
|
+
return function () {
|
|
24
|
+
let t = (seed += 0x6d2b79f5);
|
|
25
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
26
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
27
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
32
28
|
};
|
|
33
29
|
}
|
|
34
30
|
// Mulberry32 is x4 faster than Math.random()
|
|
35
31
|
// Benchmark: https://jsbm.dev/muLCWR9RJCbmy
|
|
36
32
|
// Spectral test: /demo/mulberry32.html
|
|
37
|
-
const prng =
|
|
33
|
+
const prng = mulberry32((Math.random() * 4294967296) | 0);
|
|
38
34
|
class CanvasParticles {
|
|
39
35
|
/** Version of the library, injected via Rollup replace plugin. */
|
|
40
|
-
static version = "4.5.
|
|
36
|
+
static version = "4.5.5";
|
|
41
37
|
static MAX_DT = 1000 / 30; // milliseconds between updates @ 30 FPS
|
|
42
38
|
static BASE_DT = 1000 / 60; // milliseconds between updates @ 60 FPS
|
|
43
39
|
/** Defines mouse interaction types with the particles */
|
|
@@ -495,6 +491,7 @@ class CanvasParticles {
|
|
|
495
491
|
const halfMaxDistSq = (maxDist / 2) ** 2;
|
|
496
492
|
const invCellSize = 1 / maxDist;
|
|
497
493
|
const stride = Math.ceil(this.width * invCellSize);
|
|
494
|
+
const rows = Math.ceil(this.height * invCellSize);
|
|
498
495
|
const drawAll = maxDist >= Math.min(this.canvas.width, this.canvas.height);
|
|
499
496
|
const maxWorkPerParticle = maxDistSq * this.option.particles.maxWork;
|
|
500
497
|
const alpha = this.color.alpha;
|
|
@@ -569,22 +566,22 @@ class CanvasParticles {
|
|
|
569
566
|
let cell;
|
|
570
567
|
if ((cell = grid.get(key + 1)))
|
|
571
568
|
renderConnectionsToCell(cell, pa); // (+1, 0)
|
|
572
|
-
if (
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
569
|
+
if (allowWork) {
|
|
570
|
+
if ((cell = grid.get(key + stride)))
|
|
571
|
+
renderConnectionsToCell(cell, pa); // (0, +1)
|
|
572
|
+
if (allowWork) {
|
|
573
|
+
if ((cell = grid.get(key + stride + 1)))
|
|
574
|
+
renderConnectionsToCell(cell, pa); // (+1, +1)
|
|
575
|
+
if (allowWork) {
|
|
576
|
+
if ((cell = grid.get(key + stride - 1)))
|
|
577
|
+
renderConnectionsToCell(cell, pa); // (-1, +1)
|
|
578
|
+
if (allowWork) {
|
|
579
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
580
|
+
renderConnectionsToOwnCell(cell || [], a, pa);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
588
585
|
// Next iteration
|
|
589
586
|
if (++a >= len)
|
|
590
587
|
break;
|
|
@@ -597,22 +594,22 @@ class CanvasParticles {
|
|
|
597
594
|
key = cellX + Math.imul(cellY, stride);
|
|
598
595
|
if ((cell = grid.get(key + stride + 1)))
|
|
599
596
|
renderConnectionsToCell(cell, pa); // (+1, +1)
|
|
600
|
-
if (
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
597
|
+
if (allowWork) {
|
|
598
|
+
if ((cell = grid.get(key + stride - 1)))
|
|
599
|
+
renderConnectionsToCell(cell, pa); // (-1, +1)
|
|
600
|
+
if (allowWork) {
|
|
601
|
+
if ((cell = grid.get(key + 1)))
|
|
602
|
+
renderConnectionsToCell(cell, pa); // (+1, 0)
|
|
603
|
+
if (allowWork) {
|
|
604
|
+
if ((cell = grid.get(key + stride)))
|
|
605
|
+
renderConnectionsToCell(cell, pa); // (0, +1)
|
|
606
|
+
if (allowWork) {
|
|
607
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
608
|
+
renderConnectionsToOwnCell(cell || [], a, pa);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
616
613
|
// Next iteration
|
|
617
614
|
if (++a >= len)
|
|
618
615
|
break;
|
|
@@ -631,7 +628,7 @@ class CanvasParticles {
|
|
|
631
628
|
renderConnectionsToCell(cell, pa); // (+1, 0)
|
|
632
629
|
if (!allowWork)
|
|
633
630
|
continue;
|
|
634
|
-
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
|
|
631
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
635
632
|
renderConnectionsToOwnCell(cell || [], a, pa);
|
|
636
633
|
if (!allowWork)
|
|
637
634
|
continue;
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(t="undefined"!=typeof globalThis?globalThis:t||self).CanvasParticles=i()}(this,function(){"use strict";function t(t,i,e,s){if(null==i)return e;const{min:n=-1/0,max:a=1/0}=s??{};return i<n?console.warn(`option.${t} was clamped to ${n} as ${i} is too low`):i>a&&console.warn(`option.${t} was clamped to ${a} as ${i} is too high`),function(t,i){return isNaN(+t)?i:+t}(Math.min(Math.max(i??e,n),a),e)}const i=2*Math.PI;const e=function(t){let i=t>>>0;return{next(){let t=i+1831565813|0;return i=t,t=Math.imul(t^t>>>15,1|t),t^=t+Math.imul(t^t>>>7,61|t),((t^t>>>14)>>>0)/4294967296}}}(4294967296*Math.random()).next;class CanvasParticles{static version="4.5.4";static MAX_DT=1e3/30;static BASE_DT=1e3/60;static interactionType=Object.freeze({NONE:0,SHIFT:1,MOVE:2});static generationType=Object.freeze({OFF:0,NEW:1,MATCH:2});static canvasIntersectionObserver=new IntersectionObserver(t=>{for(const i of t){const t=i.target,e=t.instance;if(!e.options?.animation)return;(t.inViewbox=i.isIntersecting)?e.option.animation?.startOnEnter&&e.start({auto:!0}):e.option.animation?.stopOnLeave&&e.stop({auto:!0,clear:!1})}},{rootMargin:"-1px"});static canvasResizeObserver=new ResizeObserver(t=>{for(const i of t){i.target.instance.updateCanvasRect()}const i=window.devicePixelRatio||1;for(const e of t){e.target.instance.#t(i)}});static instances=new Set;canvas;ctx;enableAnimating=!1;isAnimating=!1;lastAnimationFrame=0;particles=[];hasManualParticles=!1;clientX=1/0;clientY=1/0;mouseX=1/0;mouseY=1/0;dpr=1;width;height;offX;offY;option;color;constructor(t,i={}){let e;if(t instanceof HTMLCanvasElement)e=t;else{if("string"!=typeof t)throw new TypeError("selector is not a string and neither a HTMLCanvasElement itself");if(e=document.querySelector(t),!(e instanceof HTMLCanvasElement))throw new Error("selector does not point to a canvas")}this.canvas=e,this.canvas.instance=this,this.canvas.inViewbox=!0;const s=this.canvas.getContext("2d");if(!s)throw new Error("failed to get 2D context from canvas");this.ctx=s,this.options=i,CanvasParticles.instances.add(this),CanvasParticles.canvasIntersectionObserver.observe(this.canvas),CanvasParticles.canvasResizeObserver.observe(this.canvas)}updateCanvasRect(){const{top:t,left:i,width:e,height:s}=this.canvas.getBoundingClientRect();this.canvas.rect={top:t,left:i,width:e,height:s}}handleMouseMove(t){this.enableAnimating&&(this.clientX=t.clientX,this.clientY=t.clientY,this.isAnimating&&this.updateMousePos())}handleScroll(){this.enableAnimating&&(this.updateCanvasRect(),this.isAnimating&&this.updateMousePos())}updateMousePos(){const{top:t,left:i}=this.canvas.rect;this.mouseX=this.clientX-i,this.mouseY=this.clientY-t}#t(t=window.devicePixelRatio||1){t<1&&(t=1);const i=this.canvas.width=this.canvas.rect.width*t,e=this.canvas.height=this.canvas.rect.height*t;t>1&&this.ctx.scale(t,t),this.mouseX=1/0,this.mouseY=1/0,this.width=Math.max(i+2*this.option.particles.connectDist,1),this.height=Math.max(e+2*this.option.particles.connectDist,1),this.offX=(i-this.width)/2,this.offY=(e-this.height)/2;const s=this.option.particles.generationType;s!==CanvasParticles.generationType.OFF&&(s===CanvasParticles.generationType.NEW||0===this.particles.length?this.newParticles():s===CanvasParticles.generationType.MATCH&&this.matchParticleCount({updateBounds:!0})),this.isAnimating&&this.#i()}resizeCanvas(t=!0){t&&this.updateCanvasRect(),this.#t()}#e(){let t=Math.round(this.option.particles.ppm*this.width*this.height/1e6);if(t=Math.min(this.option.particles.max,t),!isFinite(t))throw new RangeError("particleCount must be finite");return 0|t}newParticles({keepAuto:t=!1,keepManual:i=!0}={}){const e=this.#e();if(this.hasManualParticles&&(t||i)?(this.particles=this.particles.filter(e=>t&&!e.isManual||i&&e.isManual),this.hasManualParticles=this.particles.length>0):this.particles=[],!t)for(let t=0;t<e;t++)this.#s()}matchParticleCount({updateBounds:t=!1}={}){const i=this.#e();if(this.hasManualParticles){const t=[];let e=0;for(const s of this.particles)s.isManual?t.push(s):e<i&&(t.push(s),e++);this.particles=t}else this.particles=this.particles.slice(0,i);if(t)for(const t of this.particles)this.#n(t);for(let t=this.particles.length;t<i;t++)this.#s()}#s(){const t=e()*this.width,s=e()*this.height;this.createParticle(t,s,e()*i,(.5+.5*e())*this.option.particles.relSpeed,(.5+2*Math.pow(e(),5))*this.option.particles.relSize,!1)}createParticle(t,i,e,s,n,a=!0){const o={posX:t,posY:i,x:t,y:i,velX:0,velY:0,offX:0,offY:0,dir:e,speed:s,size:n,gridPos:{x:1,y:1},isVisible:!1,isManual:a,bounds:{top:-n,right:this.canvas.width+n,bottom:this.canvas.height+n,left:-n}};this.particles.push(o),this.hasManualParticles=!0}#a(t){t.bounds.top=-t.size,t.bounds.right=this.canvas.width+t.size,t.bounds.bottom=this.canvas.height+t.size,t.bounds.left=-t.size}#n(t){t.bounds.right=this.canvas.width+t.size,t.bounds.bottom=this.canvas.height+t.size}updateParticles(){const t=this.option.particles.relSpeed,i=this.option.particles.relSize;for(const s of this.particles)s.speed=(.5+.5*e())*t,s.size=(.5+2*Math.pow(e(),5))*i,this.#a(s)}#o(t){const i=this.option.gravity.repulsive>0,e=this.option.gravity.pulling>0;if(!i&&!e)return;const s=this.particles,n=s.length,a=this.option.particles.connectDist,o=a*this.option.gravity.repulsive*t,r=a*this.option.gravity.pulling*t,c=(a/2)**2,l=a**2/256;for(let t=0;t<n;t++){const i=s[t];for(let a=t+1;a<n;a++){const t=s[a],n=i.posX-t.posX,h=i.posY-t.posY,p=n*n+h*h;if(p>=c&&!e)continue;const d=1/Math.sqrt(p+l),u=d*d*d;if(p<c){const e=u*o,s=-n*e,a=-h*e;i.velX-=s,i.velY-=a,t.velX+=s,t.velY+=a}if(!e)continue;const f=u*r,g=-n*f,v=-h*f;i.velX+=g,i.velY+=v,t.velX-=g,t.velY-=v}}}#r(t){const e=this.width,s=this.height,n=this.offX,a=this.offY,o=this.mouseX,r=this.mouseY,c=this.option.mouse.interactionType===CanvasParticles.interactionType.NONE,l=this.option.mouse.interactionType===CanvasParticles.interactionType.MOVE,h=this.option.mouse.connectDist,p=this.option.mouse.distRatio,d=this.option.particles.rotationSpeed*t,u=this.option.gravity.friction,f=this.option.gravity.maxVelocity,g=1-Math.pow(3/4,t);for(const v of this.particles){v.dir+=2*(Math.random()-.5)*d*t,v.dir%=i;const m=Math.sin(v.dir)*v.speed,x=Math.cos(v.dir)*v.speed;f>0&&(v.velX>f&&(v.velX=f),v.velX<-f&&(v.velX=-f),v.velY>f&&(v.velY=f),v.velY<-f&&(v.velY=-f)),v.posX+=(m+v.velX)*t,v.posY+=(x+v.velY)*t,v.posX%=e,v.posX<0&&(v.posX+=e),v.posY%=s,v.posY<0&&(v.posY+=s),v.velX*=Math.pow(u,t),v.velY*=Math.pow(u,t);const y=v.posX+n-o,b=v.posY+a-r;if(!c){const t=h/Math.hypot(y,b);p<t?(v.offX+=(t*y-y-v.offX)*g,v.offY+=(t*b-b-v.offY)*g):(v.offX-=v.offX*g,v.offY-=v.offY*g)}v.x=v.posX+v.offX,v.y=v.posY+v.offY,l&&(v.posX=v.x,v.posY=v.y),v.x+=n,v.y+=a,v.gridPos.x=+(v.x>=v.bounds.left)+ +(v.x>v.bounds.right),v.gridPos.y=+(v.y>=v.bounds.top)+ +(v.y>v.bounds.bottom),v.isVisible=1===v.gridPos.x&&1===v.gridPos.y}}#c(){const t=this.ctx,e=window.devicePixelRatio||1;for(const s of this.particles)s.isVisible&&(s.size>1/e?(t.beginPath(),t.arc(s.x,s.y,s.size,0,i),t.fill(),t.closePath()):t.fillRect(s.x-s.size,s.y-s.size,2*s.size,2*s.size))}#l(t,i){const e=this.particles,s=e.length,n=new Map;for(let a=0;a<s;a++){const s=e[a],o=(s.x*i|0)+Math.imul(s.y*i,t),r=n.get(o);r?r.push(a):n.set(o,[a])}return n}static#h(t,i){return!(!t.isVisible&&!i.isVisible)||!(t.gridPos.x===i.gridPos.x&&1!==t.gridPos.x||t.gridPos.y===i.gridPos.y&&1!==t.gridPos.y)}#p(){const t=this.particles,i=t.length,e=this.ctx,s=this.option.particles.connectDist,n=s**2,a=(s/2)**2,o=1/s,r=Math.ceil(this.width*o),c=s>=Math.min(this.canvas.width,this.canvas.height),l=n*this.option.particles.maxWork,h=this.color.alpha,p=this.color.alpha*s,d=[],u=this.#l(r,o);let f=0,g=!0;function v(t,i,s,o){const r=t-s,c=i-o,u=r*r+c*c;u>n||(u>a?(e.globalAlpha=p/Math.sqrt(u)-h,e.beginPath(),e.moveTo(t,i),e.lineTo(s,o),e.stroke()):d.push(t,i,s,o),f+=u,g=f<l)}function m(i,e,s){for(const n of i){if(e>=n)continue;const i=t[n];if((c||CanvasParticles.#h(s,i))&&(v(s.x,s.y,i.x,i.y),!g))break}}function x(i,e){for(const s of i){const i=t[s];if((c||CanvasParticles.#h(e,i))&&(v(e.x,e.y,i.x,i.y),!g))break}}for(let e=0;e<i;e++){f=0,g=!0;let s,n=t[e],a=n.x*o|0,c=n.y*o|0,l=a+Math.imul(c,r);if((s=u.get(l+1))&&x(s,n),g&&((s=u.get(l+r))&&x(s,n),g&&((s=u.get(l+r+1))&&x(s,n),g&&((s=u.get(l+r-1))&&x(s,n),g)))){if(a>=0&&c>=0&&a<r-2&&(s=u.get(l))&&m(s||[],e,n),++e>=i)break;if(f=0,g=!0,n=t[e],a=n.x*o|0,c=n.y*o|0,l=a+Math.imul(c,r),(s=u.get(l+r+1))&&x(s,n),g&&((s=u.get(l+r-1))&&x(s,n),g&&((s=u.get(l+1))&&x(s,n),g&&((s=u.get(l+r))&&x(s,n),g)))){if(a>=0&&c>=0&&a<r-2&&(s=u.get(l))&&m(s||[],e,n),++e>=i)break;f=0,g=!0,n=t[e],a=n.x*o|0,c=n.y*o|0,l=a+Math.imul(c,r),(s=u.get(l+r))&&x(s,n),g&&((s=u.get(l+1))&&x(s,n),g&&(a>=0&&c>=0&&a<r-2&&(s=u.get(l))&&m(s||[],e,n),g&&((s=u.get(l+r-1))&&x(s,n),g&&(s=u.get(l+r+1))&&x(s,n))))}}}if(d.length){e.globalAlpha=h,e.beginPath();for(let t=0;t<d.length;t+=4)e.moveTo(d[t],d[t+1]),e.lineTo(d[t+2],d[t+3]);e.stroke()}}#d(t){const i=this.ctx,{width:e,height:s}=this.canvas;i.save(),i.globalAlpha=.5,i.beginPath();for(let n=.5;n<=e;n+=t)i.moveTo(n,0),i.lineTo(n,s);for(let n=.5;n<=s;n+=t)i.moveTo(0,n),i.lineTo(e,n);i.stroke(),i.restore()}#u(){const t=this.ctx,i=this.particles,e=i.length;t.save(),t.globalAlpha=1,t.fillStyle="#fff",t.textAlign="center",t.textBaseline="middle";for(let s=0;s<e;s++){const e=i[s];t.fillText(String(s),e.x,e.y)}t.restore()}#f(){const t=performance.now(),i=Math.min(t-this.lastAnimationFrame,CanvasParticles.MAX_DT)/CanvasParticles.BASE_DT;this.#o(i),this.#r(i),this.lastAnimationFrame=t}#i(){this.ctx.clearRect(0,0,this.canvas.rect.width,this.canvas.rect.height),this.ctx.globalAlpha=this.color.alpha,this.ctx.fillStyle=this.color.hex,this.ctx.strokeStyle=this.color.hex,this.ctx.lineWidth=1,this.#c(),this.option.particles.drawLines&&this.#p(),this.option.debug.drawGrid&&this.#d(this.option.particles.connectDist),this.option.debug.drawIndexes&&this.#u()}#g(){this.isAnimating&&(requestAnimationFrame(()=>this.#g()),this.#f(),this.#i())}start({auto:t=!1}={}){return this.isAnimating||t&&!this.enableAnimating||(this.enableAnimating=!0,this.isAnimating=!0,this.updateCanvasRect(),requestAnimationFrame(()=>this.#g())),!this.canvas.inViewbox&&this.option.animation.startOnEnter&&(this.isAnimating=!1),this}stop({auto:t=!1,clear:i=!0}={}){return t||(this.enableAnimating=!1),this.isAnimating=!1,!1!==i&&this.ctx.clearRect(0,0,this.canvas.rect.width,this.canvas.rect.height),!0}destroy(){this.stop(),CanvasParticles.instances.delete(this),CanvasParticles.canvasIntersectionObserver.unobserve(this.canvas),CanvasParticles.canvasResizeObserver.unobserve(this.canvas),this.canvas?.remove(),Object.keys(this).forEach(t=>delete this[t])}set options(i){const e=t;this.option={background:i.background??!1,animation:{startOnEnter:!!(i.animation?.startOnEnter??1),stopOnLeave:!!(i.animation?.stopOnLeave??1)},mouse:{interactionType:~~e("mouse.interactionType",i.mouse?.interactionType,CanvasParticles.interactionType.MOVE,{min:0,max:2}),connectDist:1,distRatio:e("mouse.distRatio",i.mouse?.distRatio,2/3,{min:0})},particles:{generationType:~~e("particles.generationType",i.particles?.generationType,CanvasParticles.generationType.MATCH,{min:0,max:2}),drawLines:!!(i.particles?.drawLines??1),color:i.particles?.color??"black",ppm:~~e("particles.ppm",i.particles?.ppm,100),max:Math.round(e("particles.max",i.particles?.max,1/0,{min:0})),maxWork:Math.round(e("particles.maxWork",i.particles?.maxWork,1/0,{min:0})),connectDist:~~e("particles.connectDistance",i.particles?.connectDistance,150,{min:1}),relSpeed:e("particles.relSpeed",i.particles?.relSpeed,1,{min:0}),relSize:e("particles.relSize",i.particles?.relSize,1,{min:0}),rotationSpeed:e("particles.rotationSpeed",i.particles?.rotationSpeed,2,{min:0})/100},gravity:{repulsive:e("gravity.repulsive",i.gravity?.repulsive,0,{min:0}),pulling:e("gravity.pulling",i.gravity?.pulling,0,{min:0}),friction:e("gravity.friction",i.gravity?.friction,.8,{min:0,max:1}),maxVelocity:e("gravity.maxVelocity",i.gravity?.maxVelocity,1/0,{min:0})},debug:{drawGrid:!!i.debug?.drawGrid,drawIndexes:!!i.debug?.drawIndexes}},this.setBackground(this.option.background),this.setMouseConnectDistMult(i.mouse?.connectDistMult),this.setParticleColor(this.option.particles.color)}get options(){return this.option}setBackground(t){if(t){if("string"!=typeof t)throw new TypeError("background is not a string");this.canvas.style.background=this.option.background=t}}setMouseConnectDistMult(i){const e=t("mouse.connectDistMult",i,2/3,{min:0});this.option.mouse.connectDist=this.option.particles.connectDist*e}setParticleColor(t){if(this.ctx.fillStyle=t,"#"===String(this.ctx.fillStyle)[0])this.color={hex:String(this.ctx.fillStyle),alpha:1};else{let t=String(this.ctx.fillStyle).split(",").at(-1);t=t?.slice(1,-1)??"1",this.ctx.fillStyle=String(this.ctx.fillStyle).split(",").slice(0,-1).join(",")+", 1)",this.color={hex:String(this.ctx.fillStyle),alpha:isNaN(+t)?1:+t}}}}return window.addEventListener("mousemove",t=>{for(const i of CanvasParticles.instances)i.handleMouseMove(t)},{passive:!0}),window.addEventListener("scroll",()=>{for(const t of CanvasParticles.instances)t.handleScroll()},{passive:!0}),CanvasParticles});
|
|
1
|
+
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(t="undefined"!=typeof globalThis?globalThis:t||self).CanvasParticles=i()}(this,function(){"use strict";function t(t,i,e,s){if(null==i)return e;const{min:a=-1/0,max:n=1/0}=s??{};return i<a?console.warn(`option.${t} was clamped to ${a} as ${i} is too low`):i>n&&console.warn(`option.${t} was clamped to ${n} as ${i} is too high`),function(t,i){return isNaN(+t)?i:+t}(Math.min(Math.max(i??e,a),n),e)}const i=2*Math.PI;const e=(s=4294967296*Math.random()|0,function(){let t=s+=1831565813;return t=Math.imul(t^t>>>15,1|t),t^=t+Math.imul(t^t>>>7,61|t),((t^t>>>14)>>>0)/4294967296});var s;class CanvasParticles{static version="4.5.5";static MAX_DT=1e3/30;static BASE_DT=1e3/60;static interactionType=Object.freeze({NONE:0,SHIFT:1,MOVE:2});static generationType=Object.freeze({OFF:0,NEW:1,MATCH:2});static canvasIntersectionObserver=new IntersectionObserver(t=>{for(const i of t){const t=i.target,e=t.instance;if(!e.options?.animation)return;(t.inViewbox=i.isIntersecting)?e.option.animation?.startOnEnter&&e.start({auto:!0}):e.option.animation?.stopOnLeave&&e.stop({auto:!0,clear:!1})}},{rootMargin:"-1px"});static canvasResizeObserver=new ResizeObserver(t=>{for(const i of t){i.target.instance.updateCanvasRect()}const i=window.devicePixelRatio||1;for(const e of t){e.target.instance.#t(i)}});static instances=new Set;canvas;ctx;enableAnimating=!1;isAnimating=!1;lastAnimationFrame=0;particles=[];hasManualParticles=!1;clientX=1/0;clientY=1/0;mouseX=1/0;mouseY=1/0;dpr=1;width;height;offX;offY;option;color;constructor(t,i={}){let e;if(t instanceof HTMLCanvasElement)e=t;else{if("string"!=typeof t)throw new TypeError("selector is not a string and neither a HTMLCanvasElement itself");if(e=document.querySelector(t),!(e instanceof HTMLCanvasElement))throw new Error("selector does not point to a canvas")}this.canvas=e,this.canvas.instance=this,this.canvas.inViewbox=!0;const s=this.canvas.getContext("2d");if(!s)throw new Error("failed to get 2D context from canvas");this.ctx=s,this.options=i,CanvasParticles.instances.add(this),CanvasParticles.canvasIntersectionObserver.observe(this.canvas),CanvasParticles.canvasResizeObserver.observe(this.canvas)}updateCanvasRect(){const{top:t,left:i,width:e,height:s}=this.canvas.getBoundingClientRect();this.canvas.rect={top:t,left:i,width:e,height:s}}handleMouseMove(t){this.enableAnimating&&(this.clientX=t.clientX,this.clientY=t.clientY,this.isAnimating&&this.updateMousePos())}handleScroll(){this.enableAnimating&&(this.updateCanvasRect(),this.isAnimating&&this.updateMousePos())}updateMousePos(){const{top:t,left:i}=this.canvas.rect;this.mouseX=this.clientX-i,this.mouseY=this.clientY-t}#t(t=window.devicePixelRatio||1){t<1&&(t=1);const i=this.canvas.width=this.canvas.rect.width*t,e=this.canvas.height=this.canvas.rect.height*t;t>1&&this.ctx.scale(t,t),this.mouseX=1/0,this.mouseY=1/0,this.width=Math.max(i+2*this.option.particles.connectDist,1),this.height=Math.max(e+2*this.option.particles.connectDist,1),this.offX=(i-this.width)/2,this.offY=(e-this.height)/2;const s=this.option.particles.generationType;s!==CanvasParticles.generationType.OFF&&(s===CanvasParticles.generationType.NEW||0===this.particles.length?this.newParticles():s===CanvasParticles.generationType.MATCH&&this.matchParticleCount({updateBounds:!0})),this.isAnimating&&this.#i()}resizeCanvas(t=!0){t&&this.updateCanvasRect(),this.#t()}#e(){let t=Math.round(this.option.particles.ppm*this.width*this.height/1e6);if(t=Math.min(this.option.particles.max,t),!isFinite(t))throw new RangeError("particleCount must be finite");return 0|t}newParticles({keepAuto:t=!1,keepManual:i=!0}={}){const e=this.#e();if(this.hasManualParticles&&(t||i)?(this.particles=this.particles.filter(e=>t&&!e.isManual||i&&e.isManual),this.hasManualParticles=this.particles.length>0):this.particles=[],!t)for(let t=0;t<e;t++)this.#s()}matchParticleCount({updateBounds:t=!1}={}){const i=this.#e();if(this.hasManualParticles){const t=[];let e=0;for(const s of this.particles)s.isManual?t.push(s):e<i&&(t.push(s),e++);this.particles=t}else this.particles=this.particles.slice(0,i);if(t)for(const t of this.particles)this.#a(t);for(let t=this.particles.length;t<i;t++)this.#s()}#s(){const t=e()*this.width,s=e()*this.height;this.createParticle(t,s,e()*i,(.5+.5*e())*this.option.particles.relSpeed,(.5+2*Math.pow(e(),5))*this.option.particles.relSize,!1)}createParticle(t,i,e,s,a,n=!0){const o={posX:t,posY:i,x:t,y:i,velX:0,velY:0,offX:0,offY:0,dir:e,speed:s,size:a,gridPos:{x:1,y:1},isVisible:!1,isManual:n,bounds:{top:-a,right:this.canvas.width+a,bottom:this.canvas.height+a,left:-a}};this.particles.push(o),this.hasManualParticles=!0}#n(t){t.bounds.top=-t.size,t.bounds.right=this.canvas.width+t.size,t.bounds.bottom=this.canvas.height+t.size,t.bounds.left=-t.size}#a(t){t.bounds.right=this.canvas.width+t.size,t.bounds.bottom=this.canvas.height+t.size}updateParticles(){const t=this.option.particles.relSpeed,i=this.option.particles.relSize;for(const s of this.particles)s.speed=(.5+.5*e())*t,s.size=(.5+2*Math.pow(e(),5))*i,this.#n(s)}#o(t){const i=this.option.gravity.repulsive>0,e=this.option.gravity.pulling>0;if(!i&&!e)return;const s=this.particles,a=s.length,n=this.option.particles.connectDist,o=n*this.option.gravity.repulsive*t,r=n*this.option.gravity.pulling*t,c=(n/2)**2,l=n**2/256;for(let t=0;t<a;t++){const i=s[t];for(let n=t+1;n<a;n++){const t=s[n],a=i.posX-t.posX,h=i.posY-t.posY,p=a*a+h*h;if(p>=c&&!e)continue;const d=1/Math.sqrt(p+l),u=d*d*d;if(p<c){const e=u*o,s=-a*e,n=-h*e;i.velX-=s,i.velY-=n,t.velX+=s,t.velY+=n}if(!e)continue;const g=u*r,v=-a*g,f=-h*g;i.velX+=v,i.velY+=f,t.velX-=v,t.velY-=f}}}#r(t){const e=this.width,s=this.height,a=this.offX,n=this.offY,o=this.mouseX,r=this.mouseY,c=this.option.mouse.interactionType===CanvasParticles.interactionType.NONE,l=this.option.mouse.interactionType===CanvasParticles.interactionType.MOVE,h=this.option.mouse.connectDist,p=this.option.mouse.distRatio,d=this.option.particles.rotationSpeed*t,u=this.option.gravity.friction,g=this.option.gravity.maxVelocity,v=1-Math.pow(3/4,t);for(const f of this.particles){f.dir+=2*(Math.random()-.5)*d*t,f.dir%=i;const m=Math.sin(f.dir)*f.speed,x=Math.cos(f.dir)*f.speed;g>0&&(f.velX>g&&(f.velX=g),f.velX<-g&&(f.velX=-g),f.velY>g&&(f.velY=g),f.velY<-g&&(f.velY=-g)),f.posX+=(m+f.velX)*t,f.posY+=(x+f.velY)*t,f.posX%=e,f.posX<0&&(f.posX+=e),f.posY%=s,f.posY<0&&(f.posY+=s),f.velX*=Math.pow(u,t),f.velY*=Math.pow(u,t);const y=f.posX+a-o,b=f.posY+n-r;if(!c){const t=h/Math.hypot(y,b);p<t?(f.offX+=(t*y-y-f.offX)*v,f.offY+=(t*b-b-f.offY)*v):(f.offX-=f.offX*v,f.offY-=f.offY*v)}f.x=f.posX+f.offX,f.y=f.posY+f.offY,l&&(f.posX=f.x,f.posY=f.y),f.x+=a,f.y+=n,f.gridPos.x=+(f.x>=f.bounds.left)+ +(f.x>f.bounds.right),f.gridPos.y=+(f.y>=f.bounds.top)+ +(f.y>f.bounds.bottom),f.isVisible=1===f.gridPos.x&&1===f.gridPos.y}}#c(){const t=this.ctx,e=window.devicePixelRatio||1;for(const s of this.particles)s.isVisible&&(s.size>1/e?(t.beginPath(),t.arc(s.x,s.y,s.size,0,i),t.fill(),t.closePath()):t.fillRect(s.x-s.size,s.y-s.size,2*s.size,2*s.size))}#l(t,i){const e=this.particles,s=e.length,a=new Map;for(let n=0;n<s;n++){const s=e[n],o=(s.x*i|0)+Math.imul(s.y*i,t),r=a.get(o);r?r.push(n):a.set(o,[n])}return a}static#h(t,i){return!(!t.isVisible&&!i.isVisible)||!(t.gridPos.x===i.gridPos.x&&1!==t.gridPos.x||t.gridPos.y===i.gridPos.y&&1!==t.gridPos.y)}#p(){const t=this.particles,i=t.length,e=this.ctx,s=this.option.particles.connectDist,a=s**2,n=(s/2)**2,o=1/s,r=Math.ceil(this.width*o),c=Math.ceil(this.height*o),l=s>=Math.min(this.canvas.width,this.canvas.height),h=a*this.option.particles.maxWork,p=this.color.alpha,d=this.color.alpha*s,u=[],g=this.#l(r,o);let v=0,f=!0;function m(t,i,s,o){const r=t-s,c=i-o,l=r*r+c*c;l>a||(l>n?(e.globalAlpha=d/Math.sqrt(l)-p,e.beginPath(),e.moveTo(t,i),e.lineTo(s,o),e.stroke()):u.push(t,i,s,o),v+=l,f=v<h)}function x(i,e,s){for(const a of i){if(e>=a)continue;const i=t[a];if((l||CanvasParticles.#h(s,i))&&(m(s.x,s.y,i.x,i.y),!f))break}}function y(i,e){for(const s of i){const i=t[s];if((l||CanvasParticles.#h(e,i))&&(m(e.x,e.y,i.x,i.y),!f))break}}for(let e=0;e<i;e++){v=0,f=!0;let s,a=t[e],n=a.x*o|0,l=a.y*o|0,h=n+Math.imul(l,r);if((s=g.get(h+1))&&y(s,a),f&&((s=g.get(h+r))&&y(s,a),f&&((s=g.get(h+r+1))&&y(s,a),f&&((s=g.get(h+r-1))&&y(s,a),f&&n>=0&&l>=0&&n<r-2&&l<c-2&&(s=g.get(h))&&x(s||[],e,a)))),++e>=i)break;if(v=0,f=!0,a=t[e],n=a.x*o|0,l=a.y*o|0,h=n+Math.imul(l,r),(s=g.get(h+r+1))&&y(s,a),f&&((s=g.get(h+r-1))&&y(s,a),f&&((s=g.get(h+1))&&y(s,a),f&&((s=g.get(h+r))&&y(s,a),f&&n>=0&&l>=0&&n<r-2&&l<c-2&&(s=g.get(h))&&x(s||[],e,a)))),++e>=i)break;v=0,f=!0,a=t[e],n=a.x*o|0,l=a.y*o|0,h=n+Math.imul(l,r),(s=g.get(h+r))&&y(s,a),f&&((s=g.get(h+1))&&y(s,a),f&&(n>=0&&l>=0&&n<r-2&&l<c-2&&(s=g.get(h))&&x(s||[],e,a),f&&((s=g.get(h+r-1))&&y(s,a),f&&(s=g.get(h+r+1))&&y(s,a))))}if(u.length){e.globalAlpha=p,e.beginPath();for(let t=0;t<u.length;t+=4)e.moveTo(u[t],u[t+1]),e.lineTo(u[t+2],u[t+3]);e.stroke()}}#d(t){const i=this.ctx,{width:e,height:s}=this.canvas;i.save(),i.globalAlpha=.5,i.beginPath();for(let a=.5;a<=e;a+=t)i.moveTo(a,0),i.lineTo(a,s);for(let a=.5;a<=s;a+=t)i.moveTo(0,a),i.lineTo(e,a);i.stroke(),i.restore()}#u(){const t=this.ctx,i=this.particles,e=i.length;t.save(),t.globalAlpha=1,t.fillStyle="#fff",t.textAlign="center",t.textBaseline="middle";for(let s=0;s<e;s++){const e=i[s];t.fillText(String(s),e.x,e.y)}t.restore()}#g(){const t=performance.now(),i=Math.min(t-this.lastAnimationFrame,CanvasParticles.MAX_DT)/CanvasParticles.BASE_DT;this.#o(i),this.#r(i),this.lastAnimationFrame=t}#i(){this.ctx.clearRect(0,0,this.canvas.rect.width,this.canvas.rect.height),this.ctx.globalAlpha=this.color.alpha,this.ctx.fillStyle=this.color.hex,this.ctx.strokeStyle=this.color.hex,this.ctx.lineWidth=1,this.#c(),this.option.particles.drawLines&&this.#p(),this.option.debug.drawGrid&&this.#d(this.option.particles.connectDist),this.option.debug.drawIndexes&&this.#u()}#v(){this.isAnimating&&(requestAnimationFrame(()=>this.#v()),this.#g(),this.#i())}start({auto:t=!1}={}){return this.isAnimating||t&&!this.enableAnimating||(this.enableAnimating=!0,this.isAnimating=!0,this.updateCanvasRect(),requestAnimationFrame(()=>this.#v())),!this.canvas.inViewbox&&this.option.animation.startOnEnter&&(this.isAnimating=!1),this}stop({auto:t=!1,clear:i=!0}={}){return t||(this.enableAnimating=!1),this.isAnimating=!1,!1!==i&&this.ctx.clearRect(0,0,this.canvas.rect.width,this.canvas.rect.height),!0}destroy(){this.stop(),CanvasParticles.instances.delete(this),CanvasParticles.canvasIntersectionObserver.unobserve(this.canvas),CanvasParticles.canvasResizeObserver.unobserve(this.canvas),this.canvas?.remove(),Object.keys(this).forEach(t=>delete this[t])}set options(i){const e=t;this.option={background:i.background??!1,animation:{startOnEnter:!!(i.animation?.startOnEnter??1),stopOnLeave:!!(i.animation?.stopOnLeave??1)},mouse:{interactionType:~~e("mouse.interactionType",i.mouse?.interactionType,CanvasParticles.interactionType.MOVE,{min:0,max:2}),connectDist:1,distRatio:e("mouse.distRatio",i.mouse?.distRatio,2/3,{min:0})},particles:{generationType:~~e("particles.generationType",i.particles?.generationType,CanvasParticles.generationType.MATCH,{min:0,max:2}),drawLines:!!(i.particles?.drawLines??1),color:i.particles?.color??"black",ppm:~~e("particles.ppm",i.particles?.ppm,100),max:Math.round(e("particles.max",i.particles?.max,1/0,{min:0})),maxWork:Math.round(e("particles.maxWork",i.particles?.maxWork,1/0,{min:0})),connectDist:~~e("particles.connectDistance",i.particles?.connectDistance,150,{min:1}),relSpeed:e("particles.relSpeed",i.particles?.relSpeed,1,{min:0}),relSize:e("particles.relSize",i.particles?.relSize,1,{min:0}),rotationSpeed:e("particles.rotationSpeed",i.particles?.rotationSpeed,2,{min:0})/100},gravity:{repulsive:e("gravity.repulsive",i.gravity?.repulsive,0,{min:0}),pulling:e("gravity.pulling",i.gravity?.pulling,0,{min:0}),friction:e("gravity.friction",i.gravity?.friction,.8,{min:0,max:1}),maxVelocity:e("gravity.maxVelocity",i.gravity?.maxVelocity,1/0,{min:0})},debug:{drawGrid:!!i.debug?.drawGrid,drawIndexes:!!i.debug?.drawIndexes}},this.setBackground(this.option.background),this.setMouseConnectDistMult(i.mouse?.connectDistMult),this.setParticleColor(this.option.particles.color)}get options(){return this.option}setBackground(t){if(t){if("string"!=typeof t)throw new TypeError("background is not a string");this.canvas.style.background=this.option.background=t}}setMouseConnectDistMult(i){const e=t("mouse.connectDistMult",i,2/3,{min:0});this.option.mouse.connectDist=this.option.particles.connectDist*e}setParticleColor(t){if(this.ctx.fillStyle=t,"#"===String(this.ctx.fillStyle)[0])this.color={hex:String(this.ctx.fillStyle),alpha:1};else{let t=String(this.ctx.fillStyle).split(",").at(-1);t=t?.slice(1,-1)??"1",this.ctx.fillStyle=String(this.ctx.fillStyle).split(",").slice(0,-1).join(",")+", 1)",this.color={hex:String(this.ctx.fillStyle),alpha:isNaN(+t)?1:+t}}}}return window.addEventListener("mousemove",t=>{for(const i of CanvasParticles.instances)i.handleMouseMove(t)},{passive:!0}),window.addEventListener("scroll",()=>{for(const t of CanvasParticles.instances)t.handleScroll()},{passive:!0}),CanvasParticles});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canvasparticles-js",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.5",
|
|
4
4
|
"description": "In an HTML canvas, a bunch of interactive particles connected with lines when they approach each other.",
|
|
5
5
|
"author": "Khoeckman",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"@rollup/plugin-replace": "^6.0.3",
|
|
30
30
|
"@rollup/plugin-terser": "^1.0.0",
|
|
31
31
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
32
|
-
"@types/node": "^25.5.
|
|
32
|
+
"@types/node": "^25.5.2",
|
|
33
33
|
"prettier": "^3.8.1",
|
|
34
|
-
"rollup": "^4.
|
|
34
|
+
"rollup": "^4.60.1",
|
|
35
35
|
"rollup-plugin-delete": "^3.0.2",
|
|
36
36
|
"tslib": "^2.8.1",
|
|
37
|
-
"typescript": "^
|
|
37
|
+
"typescript": "^6.0.2"
|
|
38
38
|
},
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -9,24 +9,19 @@ import type { CanvasParticlesOptions, CanvasParticlesOptionsInput } from './type
|
|
|
9
9
|
const TWO_PI = 2 * Math.PI
|
|
10
10
|
|
|
11
11
|
/** Extremely fast, simple 32‑bit PRNG */
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
state = t
|
|
19
|
-
t = Math.imul(t ^ (t >>> 15), t | 1)
|
|
20
|
-
t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
|
|
21
|
-
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
|
|
22
|
-
},
|
|
12
|
+
function mulberry32(seed: number) {
|
|
13
|
+
return function () {
|
|
14
|
+
let t = (seed += 0x6d2b79f5)
|
|
15
|
+
t = Math.imul(t ^ (t >>> 15), t | 1)
|
|
16
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
|
|
17
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
|
|
23
18
|
}
|
|
24
19
|
}
|
|
25
20
|
|
|
26
21
|
// Mulberry32 is x4 faster than Math.random()
|
|
27
22
|
// Benchmark: https://jsbm.dev/muLCWR9RJCbmy
|
|
28
23
|
// Spectral test: /demo/mulberry32.html
|
|
29
|
-
const prng =
|
|
24
|
+
const prng = mulberry32((Math.random() * 4294967296) | 0)
|
|
30
25
|
|
|
31
26
|
// Injected by Rollup
|
|
32
27
|
declare const __VERSION__: string
|
|
@@ -561,6 +556,7 @@ export default class CanvasParticles {
|
|
|
561
556
|
|
|
562
557
|
const invCellSize = 1 / maxDist
|
|
563
558
|
const stride = Math.ceil(this.width * invCellSize)
|
|
559
|
+
const rows = Math.ceil(this.height * invCellSize)
|
|
564
560
|
|
|
565
561
|
const drawAll = maxDist >= Math.min(this.canvas.width, this.canvas.height)
|
|
566
562
|
const maxWorkPerParticle = maxDistSq * this.option.particles.maxWork
|
|
@@ -646,15 +642,19 @@ export default class CanvasParticles {
|
|
|
646
642
|
let cell
|
|
647
643
|
|
|
648
644
|
if ((cell = grid.get(key + 1))) renderConnectionsToCell(cell, pa) // (+1, 0)
|
|
649
|
-
if (
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
645
|
+
if (allowWork) {
|
|
646
|
+
if ((cell = grid.get(key + stride))) renderConnectionsToCell(cell, pa) // (0, +1)
|
|
647
|
+
if (allowWork) {
|
|
648
|
+
if ((cell = grid.get(key + stride + 1))) renderConnectionsToCell(cell, pa) // (+1, +1)
|
|
649
|
+
if (allowWork) {
|
|
650
|
+
if ((cell = grid.get(key + stride - 1))) renderConnectionsToCell(cell, pa) // (-1, +1)
|
|
651
|
+
if (allowWork) {
|
|
652
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
653
|
+
renderConnectionsToOwnCell(cell || [], a, pa)
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
658
|
|
|
659
659
|
// Next iteration
|
|
660
660
|
if (++a >= len) break
|
|
@@ -669,15 +669,19 @@ export default class CanvasParticles {
|
|
|
669
669
|
key = cellX + Math.imul(cellY, stride)
|
|
670
670
|
|
|
671
671
|
if ((cell = grid.get(key + stride + 1))) renderConnectionsToCell(cell, pa) // (+1, +1)
|
|
672
|
-
if (
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
672
|
+
if (allowWork) {
|
|
673
|
+
if ((cell = grid.get(key + stride - 1))) renderConnectionsToCell(cell, pa) // (-1, +1)
|
|
674
|
+
if (allowWork) {
|
|
675
|
+
if ((cell = grid.get(key + 1))) renderConnectionsToCell(cell, pa) // (+1, 0)
|
|
676
|
+
if (allowWork) {
|
|
677
|
+
if ((cell = grid.get(key + stride))) renderConnectionsToCell(cell, pa) // (0, +1)
|
|
678
|
+
if (allowWork) {
|
|
679
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
680
|
+
renderConnectionsToOwnCell(cell || [], a, pa)
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
681
685
|
|
|
682
686
|
// Next iteration
|
|
683
687
|
if (++a >= len) break
|
|
@@ -695,7 +699,7 @@ export default class CanvasParticles {
|
|
|
695
699
|
if (!allowWork) continue
|
|
696
700
|
if ((cell = grid.get(key + 1))) renderConnectionsToCell(cell, pa) // (+1, 0)
|
|
697
701
|
if (!allowWork) continue
|
|
698
|
-
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
|
|
702
|
+
if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && cellY < rows - 2 && (cell = grid.get(key)))
|
|
699
703
|
renderConnectionsToOwnCell(cell || [], a, pa)
|
|
700
704
|
if (!allowWork) continue
|
|
701
705
|
if ((cell = grid.get(key + stride - 1))) renderConnectionsToCell(cell, pa) // (-1, +1)
|