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 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 Mulberry32(seed) {
25
- let state = seed >>> 0;
26
- return {
27
- next() {
28
- let t = (state + 0x6d2b79f5) | 0;
29
- state = t;
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 = Mulberry32(Math.random() * 4294967296).next;
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.4";
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 (!allowWork)
575
- continue;
576
- if ((cell = grid.get(key + stride)))
577
- renderConnectionsToCell(cell, pa); // (0, +1)
578
- if (!allowWork)
579
- continue;
580
- if ((cell = grid.get(key + stride + 1)))
581
- renderConnectionsToCell(cell, pa); // (+1, +1)
582
- if (!allowWork)
583
- continue;
584
- if ((cell = grid.get(key + stride - 1)))
585
- renderConnectionsToCell(cell, pa); // (-1, +1)
586
- if (!allowWork)
587
- continue;
588
- if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
589
- renderConnectionsToOwnCell(cell || [], a, pa);
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 (!allowWork)
603
- continue;
604
- if ((cell = grid.get(key + stride - 1)))
605
- renderConnectionsToCell(cell, pa); // (-1, +1)
606
- if (!allowWork)
607
- continue;
608
- if ((cell = grid.get(key + 1)))
609
- renderConnectionsToCell(cell, pa); // (+1, 0)
610
- if (!allowWork)
611
- continue;
612
- if ((cell = grid.get(key + stride)))
613
- renderConnectionsToCell(cell, pa); // (0, +1)
614
- if (!allowWork)
615
- continue;
616
- if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
617
- renderConnectionsToOwnCell(cell || [], a, pa);
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 Mulberry32(seed) {
23
- let state = seed >>> 0;
24
- return {
25
- next() {
26
- let t = (state + 0x6d2b79f5) | 0;
27
- state = t;
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 = Mulberry32(Math.random() * 4294967296).next;
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.4";
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 (!allowWork)
573
- continue;
574
- if ((cell = grid.get(key + stride)))
575
- renderConnectionsToCell(cell, pa); // (0, +1)
576
- if (!allowWork)
577
- continue;
578
- if ((cell = grid.get(key + stride + 1)))
579
- renderConnectionsToCell(cell, pa); // (+1, +1)
580
- if (!allowWork)
581
- continue;
582
- if ((cell = grid.get(key + stride - 1)))
583
- renderConnectionsToCell(cell, pa); // (-1, +1)
584
- if (!allowWork)
585
- continue;
586
- if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
587
- renderConnectionsToOwnCell(cell || [], a, pa);
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 (!allowWork)
601
- continue;
602
- if ((cell = grid.get(key + stride - 1)))
603
- renderConnectionsToCell(cell, pa); // (-1, +1)
604
- if (!allowWork)
605
- continue;
606
- if ((cell = grid.get(key + 1)))
607
- renderConnectionsToCell(cell, pa); // (+1, 0)
608
- if (!allowWork)
609
- continue;
610
- if ((cell = grid.get(key + stride)))
611
- renderConnectionsToCell(cell, pa); // (0, +1)
612
- if (!allowWork)
613
- continue;
614
- if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
615
- renderConnectionsToOwnCell(cell || [], a, pa);
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.4",
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.0",
32
+ "@types/node": "^25.5.2",
33
33
  "prettier": "^3.8.1",
34
- "rollup": "^4.59.0",
34
+ "rollup": "^4.60.1",
35
35
  "rollup-plugin-delete": "^3.0.2",
36
36
  "tslib": "^2.8.1",
37
- "typescript": "^5.9.3"
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 Mulberry32(seed: number) {
13
- let state = seed >>> 0
14
-
15
- return {
16
- next() {
17
- let t = (state + 0x6d2b79f5) | 0
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 = Mulberry32(Math.random() * 4294967296).next
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 (!allowWork) continue
650
- if ((cell = grid.get(key + stride))) renderConnectionsToCell(cell, pa) // (0, +1)
651
- if (!allowWork) continue
652
- if ((cell = grid.get(key + stride + 1))) renderConnectionsToCell(cell, pa) // (+1, +1)
653
- if (!allowWork) continue
654
- if ((cell = grid.get(key + stride - 1))) renderConnectionsToCell(cell, pa) // (-1, +1)
655
- if (!allowWork) continue
656
- if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
657
- renderConnectionsToOwnCell(cell || [], a, pa)
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 (!allowWork) continue
673
- if ((cell = grid.get(key + stride - 1))) renderConnectionsToCell(cell, pa) // (-1, +1)
674
- if (!allowWork) continue
675
- if ((cell = grid.get(key + 1))) renderConnectionsToCell(cell, pa) // (+1, 0)
676
- if (!allowWork) continue
677
- if ((cell = grid.get(key + stride))) renderConnectionsToCell(cell, pa) // (0, +1)
678
- if (!allowWork) continue
679
- if (cellX >= 0 && cellY >= 0 && cellX < stride - 2 && (cell = grid.get(key)))
680
- renderConnectionsToOwnCell(cell || [], a, pa)
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)