canvasparticles-js 4.5.1 → 4.5.4
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/README.md +2 -2
- package/dist/index.cjs +9 -6
- package/dist/index.mjs +9 -6
- package/dist/index.umd.js +1 -1
- package/package.json +76 -76
- package/src/index.ts +8 -5
package/README.md
CHANGED
|
@@ -354,7 +354,7 @@ instance.options = { ... }
|
|
|
354
354
|
createParticle(posX?: number, posY?: number, dir?: number, speed?: number, size?: number)
|
|
355
355
|
```
|
|
356
356
|
|
|
357
|
-
By default `particles.ppm` and `particles.max` are used to auto-generate random particles.
|
|
357
|
+
By default `particles.ppm` and `particles.max` are used to auto-generate random particles. To turn this off, set at least one of these properties to `0` or set `particles.generationType` to `OFF (0)` (slightly more efficient).
|
|
358
358
|
|
|
359
359
|
```js
|
|
360
360
|
const canvas = '#my-canvas'
|
|
@@ -391,7 +391,7 @@ instance.newParticles({ keepAuto: true, keepManual: false })
|
|
|
391
391
|
left: 0;
|
|
392
392
|
width: 100%;
|
|
393
393
|
height: 100%;
|
|
394
|
-
z-index: -1;
|
|
394
|
+
z-index: -1;
|
|
395
395
|
}
|
|
396
396
|
</style>
|
|
397
397
|
</head>
|
package/dist/index.cjs
CHANGED
|
@@ -33,13 +33,13 @@ function Mulberry32(seed) {
|
|
|
33
33
|
},
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
// Mulberry32 is
|
|
36
|
+
// Mulberry32 is x4 faster than Math.random()
|
|
37
37
|
// Benchmark: https://jsbm.dev/muLCWR9RJCbmy
|
|
38
38
|
// Spectral test: /demo/mulberry32.html
|
|
39
39
|
const prng = Mulberry32(Math.random() * 4294967296).next;
|
|
40
40
|
class CanvasParticles {
|
|
41
41
|
/** Version of the library, injected via Rollup replace plugin. */
|
|
42
|
-
static version = "4.5.
|
|
42
|
+
static version = "4.5.4";
|
|
43
43
|
static MAX_DT = 1000 / 30; // milliseconds between updates @ 30 FPS
|
|
44
44
|
static BASE_DT = 1000 / 60; // milliseconds between updates @ 60 FPS
|
|
45
45
|
/** Defines mouse interaction types with the particles */
|
|
@@ -162,10 +162,12 @@ class CanvasParticles {
|
|
|
162
162
|
}
|
|
163
163
|
/** Resize the canvas and update particles accordingly */
|
|
164
164
|
#resizeCanvas(dpr = window.devicePixelRatio || 1) {
|
|
165
|
+
if (dpr < 1)
|
|
166
|
+
dpr = 1;
|
|
165
167
|
const width = (this.canvas.width = this.canvas.rect.width * dpr);
|
|
166
168
|
const height = (this.canvas.height = this.canvas.rect.height * dpr);
|
|
167
169
|
// Must be set every time width or height changes because scale is removed
|
|
168
|
-
if (dpr
|
|
170
|
+
if (dpr > 1)
|
|
169
171
|
this.ctx.scale(dpr, dpr);
|
|
170
172
|
// Hide the mouse when resizing because it must be outside the viewport to do so
|
|
171
173
|
this.mouseX = Infinity;
|
|
@@ -442,11 +444,12 @@ class CanvasParticles {
|
|
|
442
444
|
/** Draw the particles on the canvas */
|
|
443
445
|
#renderParticles() {
|
|
444
446
|
const ctx = this.ctx;
|
|
447
|
+
const dpr = window.devicePixelRatio || 1;
|
|
445
448
|
for (const p of this.particles) {
|
|
446
449
|
if (!p.isVisible)
|
|
447
450
|
continue;
|
|
448
451
|
// Draw particles smaller than 1px as a square instead of a circle for performance
|
|
449
|
-
if (p.size > 1) {
|
|
452
|
+
if (p.size > 1 / dpr) {
|
|
450
453
|
// Draw circle
|
|
451
454
|
ctx.beginPath();
|
|
452
455
|
ctx.arc(p.x, p.y, p.size, 0, TWO_PI);
|
|
@@ -700,7 +703,7 @@ class CanvasParticles {
|
|
|
700
703
|
}
|
|
701
704
|
/** Clear the canvas and render the particles and their connections onto the canvas */
|
|
702
705
|
#render() {
|
|
703
|
-
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
706
|
+
this.ctx.clearRect(0, 0, this.canvas.rect.width, this.canvas.rect.height);
|
|
704
707
|
this.ctx.globalAlpha = this.color.alpha;
|
|
705
708
|
this.ctx.fillStyle = this.color.hex;
|
|
706
709
|
this.ctx.strokeStyle = this.color.hex;
|
|
@@ -740,7 +743,7 @@ class CanvasParticles {
|
|
|
740
743
|
this.enableAnimating = false;
|
|
741
744
|
this.isAnimating = false;
|
|
742
745
|
if (clear !== false)
|
|
743
|
-
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
746
|
+
this.ctx.clearRect(0, 0, this.canvas.rect.width, this.canvas.rect.height);
|
|
744
747
|
return true;
|
|
745
748
|
}
|
|
746
749
|
/** Gracefully destroy the instance and remove the canvas element */
|
package/dist/index.mjs
CHANGED
|
@@ -31,13 +31,13 @@ function Mulberry32(seed) {
|
|
|
31
31
|
},
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
// Mulberry32 is
|
|
34
|
+
// Mulberry32 is x4 faster than Math.random()
|
|
35
35
|
// Benchmark: https://jsbm.dev/muLCWR9RJCbmy
|
|
36
36
|
// Spectral test: /demo/mulberry32.html
|
|
37
37
|
const prng = Mulberry32(Math.random() * 4294967296).next;
|
|
38
38
|
class CanvasParticles {
|
|
39
39
|
/** Version of the library, injected via Rollup replace plugin. */
|
|
40
|
-
static version = "4.5.
|
|
40
|
+
static version = "4.5.4";
|
|
41
41
|
static MAX_DT = 1000 / 30; // milliseconds between updates @ 30 FPS
|
|
42
42
|
static BASE_DT = 1000 / 60; // milliseconds between updates @ 60 FPS
|
|
43
43
|
/** Defines mouse interaction types with the particles */
|
|
@@ -160,10 +160,12 @@ class CanvasParticles {
|
|
|
160
160
|
}
|
|
161
161
|
/** Resize the canvas and update particles accordingly */
|
|
162
162
|
#resizeCanvas(dpr = window.devicePixelRatio || 1) {
|
|
163
|
+
if (dpr < 1)
|
|
164
|
+
dpr = 1;
|
|
163
165
|
const width = (this.canvas.width = this.canvas.rect.width * dpr);
|
|
164
166
|
const height = (this.canvas.height = this.canvas.rect.height * dpr);
|
|
165
167
|
// Must be set every time width or height changes because scale is removed
|
|
166
|
-
if (dpr
|
|
168
|
+
if (dpr > 1)
|
|
167
169
|
this.ctx.scale(dpr, dpr);
|
|
168
170
|
// Hide the mouse when resizing because it must be outside the viewport to do so
|
|
169
171
|
this.mouseX = Infinity;
|
|
@@ -440,11 +442,12 @@ class CanvasParticles {
|
|
|
440
442
|
/** Draw the particles on the canvas */
|
|
441
443
|
#renderParticles() {
|
|
442
444
|
const ctx = this.ctx;
|
|
445
|
+
const dpr = window.devicePixelRatio || 1;
|
|
443
446
|
for (const p of this.particles) {
|
|
444
447
|
if (!p.isVisible)
|
|
445
448
|
continue;
|
|
446
449
|
// Draw particles smaller than 1px as a square instead of a circle for performance
|
|
447
|
-
if (p.size > 1) {
|
|
450
|
+
if (p.size > 1 / dpr) {
|
|
448
451
|
// Draw circle
|
|
449
452
|
ctx.beginPath();
|
|
450
453
|
ctx.arc(p.x, p.y, p.size, 0, TWO_PI);
|
|
@@ -698,7 +701,7 @@ class CanvasParticles {
|
|
|
698
701
|
}
|
|
699
702
|
/** Clear the canvas and render the particles and their connections onto the canvas */
|
|
700
703
|
#render() {
|
|
701
|
-
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
704
|
+
this.ctx.clearRect(0, 0, this.canvas.rect.width, this.canvas.rect.height);
|
|
702
705
|
this.ctx.globalAlpha = this.color.alpha;
|
|
703
706
|
this.ctx.fillStyle = this.color.hex;
|
|
704
707
|
this.ctx.strokeStyle = this.color.hex;
|
|
@@ -738,7 +741,7 @@ class CanvasParticles {
|
|
|
738
741
|
this.enableAnimating = false;
|
|
739
742
|
this.isAnimating = false;
|
|
740
743
|
if (clear !== false)
|
|
741
|
-
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
744
|
+
this.ctx.clearRect(0, 0, this.canvas.rect.width, this.canvas.rect.height);
|
|
742
745
|
return true;
|
|
743
746
|
}
|
|
744
747
|
/** Gracefully destroy the instance and remove the canvas element */
|
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:o=1/0}=s??{};return i<n?console.warn(`option.${t} was clamped to ${n} as ${i} is too low`):i>o&&console.warn(`option.${t} was clamped to ${o} as ${i} is too high`),function(t,i){return isNaN(+t)?i:+t}(Math.min(Math.max(i??e,n),o),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 s{static version="4.5.1";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 n=this.canvas.getContext("2d");if(!n)throw new Error("failed to get 2D context from canvas");this.ctx=n,this.options=i,s.instances.add(this),s.canvasIntersectionObserver.observe(this.canvas),s.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){const i=this.canvas.width=this.canvas.rect.width*t,e=this.canvas.height=this.canvas.rect.height*t;1!==t&&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 n=this.option.particles.generationType;n!==s.generationType.OFF&&(n===s.generationType.NEW||0===this.particles.length?this.newParticles():n===s.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,o=!0){const a={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:o,bounds:{top:-n,right:this.canvas.width+n,bottom:this.canvas.height+n,left:-n}};this.particles.push(a),this.hasManualParticles=!0}#o(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.#o(s)}#a(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,o=this.option.particles.connectDist,a=o*this.option.gravity.repulsive*t,r=o*this.option.gravity.pulling*t,c=(o/2)**2,l=o**2/256;for(let t=0;t<n;t++){const i=s[t];for(let o=t+1;o<n;o++){const t=s[o],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*a,s=-n*e,o=-h*e;i.velX-=s,i.velY-=o,t.velX+=s,t.velY+=o}if(!e)continue;const f=u*r,g=-n*f,m=-h*f;i.velX+=g,i.velY+=m,t.velX-=g,t.velY-=m}}}#r(t){const e=this.width,n=this.height,o=this.offX,a=this.offY,r=this.mouseX,c=this.mouseY,l=this.option.mouse.interactionType===s.interactionType.NONE,h=this.option.mouse.interactionType===s.interactionType.MOVE,p=this.option.mouse.connectDist,d=this.option.mouse.distRatio,u=this.option.particles.rotationSpeed*t,f=this.option.gravity.friction,g=this.option.gravity.maxVelocity,m=1-Math.pow(3/4,t);for(const s of this.particles){s.dir+=2*(Math.random()-.5)*u*t,s.dir%=i;const v=Math.sin(s.dir)*s.speed,x=Math.cos(s.dir)*s.speed;g>0&&(s.velX>g&&(s.velX=g),s.velX<-g&&(s.velX=-g),s.velY>g&&(s.velY=g),s.velY<-g&&(s.velY=-g)),s.posX+=(v+s.velX)*t,s.posY+=(x+s.velY)*t,s.posX%=e,s.posX<0&&(s.posX+=e),s.posY%=n,s.posY<0&&(s.posY+=n),s.velX*=Math.pow(f,t),s.velY*=Math.pow(f,t);const y=s.posX+o-r,b=s.posY+a-c;if(!l){const t=p/Math.hypot(y,b);d<t?(s.offX+=(t*y-y-s.offX)*m,s.offY+=(t*b-b-s.offY)*m):(s.offX-=s.offX*m,s.offY-=s.offY*m)}s.x=s.posX+s.offX,s.y=s.posY+s.offY,h&&(s.posX=s.x,s.posY=s.y),s.x+=o,s.y+=a,s.gridPos.x=+(s.x>=s.bounds.left)+ +(s.x>s.bounds.right),s.gridPos.y=+(s.y>=s.bounds.top)+ +(s.y>s.bounds.bottom),s.isVisible=1===s.gridPos.x&&1===s.gridPos.y}}#c(){const t=this.ctx;for(const e of this.particles)e.isVisible&&(e.size>1?(t.beginPath(),t.arc(e.x,e.y,e.size,0,i),t.fill(),t.closePath()):t.fillRect(e.x-e.size,e.y-e.size,2*e.size,2*e.size))}#l(t,i){const e=this.particles,s=e.length,n=new Map;for(let o=0;o<s;o++){const s=e[o],a=(s.x*i|0)+Math.imul(s.y*i,t),r=n.get(a);r?r.push(o):n.set(a,[o])}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,n=this.option.particles.connectDist,o=n**2,a=(n/2)**2,r=1/n,c=Math.ceil(this.width*r),l=n>=Math.min(this.canvas.width,this.canvas.height),h=o*this.option.particles.maxWork,p=this.color.alpha,d=this.color.alpha*n,u=[],f=this.#l(c,r);let g=0,m=!0;function v(t,i,s,n){const r=t-s,c=i-n,l=r*r+c*c;l>o||(l>a?(e.globalAlpha=d/Math.sqrt(l)-p,e.beginPath(),e.moveTo(t,i),e.lineTo(s,n),e.stroke()):u.push(t,i,s,n),g+=l,m=g<h)}function x(i,e,n){for(const o of i){if(e>=o)continue;const i=t[o];if((l||s.#h(n,i))&&(v(n.x,n.y,i.x,i.y),!m))break}}function y(i,e){for(const n of i){const i=t[n];if((l||s.#h(e,i))&&(v(e.x,e.y,i.x,i.y),!m))break}}for(let e=0;e<i;e++){g=0,m=!0;let s,n=t[e],o=n.x*r|0,a=n.y*r|0,l=o+Math.imul(a,c);if((s=f.get(l+1))&&y(s,n),m&&((s=f.get(l+c))&&y(s,n),m&&((s=f.get(l+c+1))&&y(s,n),m&&((s=f.get(l+c-1))&&y(s,n),m)))){if(o>=0&&a>=0&&o<c-2&&(s=f.get(l))&&x(s||[],e,n),++e>=i)break;if(g=0,m=!0,n=t[e],o=n.x*r|0,a=n.y*r|0,l=o+Math.imul(a,c),(s=f.get(l+c+1))&&y(s,n),m&&((s=f.get(l+c-1))&&y(s,n),m&&((s=f.get(l+1))&&y(s,n),m&&((s=f.get(l+c))&&y(s,n),m)))){if(o>=0&&a>=0&&o<c-2&&(s=f.get(l))&&x(s||[],e,n),++e>=i)break;g=0,m=!0,n=t[e],o=n.x*r|0,a=n.y*r|0,l=o+Math.imul(a,c),(s=f.get(l+c))&&y(s,n),m&&((s=f.get(l+1))&&y(s,n),m&&(o>=0&&a>=0&&o<c-2&&(s=f.get(l))&&x(s||[],e,n),m&&((s=f.get(l+c-1))&&y(s,n),m&&(s=f.get(l+c+1))&&y(s,n))))}}}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 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,s.MAX_DT)/s.BASE_DT;this.#a(i),this.#r(i),this.lastAnimationFrame=t}#i(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.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.width,this.canvas.height),!0}destroy(){this.stop(),s.instances.delete(this),s.canvasIntersectionObserver.unobserve(this.canvas),s.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,s.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,s.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 s.instances)i.handleMouseMove(t)},{passive:!0}),window.addEventListener("scroll",()=>{for(const t of s.instances)t.handleScroll()},{passive:!0}),s});
|
|
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});
|
package/package.json
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "canvasparticles-js",
|
|
3
|
-
"version": "4.5.
|
|
4
|
-
"description": "In an HTML canvas, a bunch of interactive particles connected with lines when they approach each other.",
|
|
5
|
-
"author": "Khoeckman",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"main": "dist/index.umd.js",
|
|
9
|
-
"module": "dist/index.mjs",
|
|
10
|
-
"types": "dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"require": "./dist/index.cjs",
|
|
15
|
-
"import": "./dist/index.mjs",
|
|
16
|
-
"default": "./dist/index.umd.js"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"src/",
|
|
21
|
-
"dist/"
|
|
22
|
-
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"test": "exit 0",
|
|
25
|
-
"build": "rollup -c",
|
|
26
|
-
"prepack": "npm run build"
|
|
27
|
-
},
|
|
28
|
-
"devDependencies": {
|
|
29
|
-
"@rollup/plugin-replace": "^6.0.3",
|
|
30
|
-
"@rollup/plugin-terser": "^0.
|
|
31
|
-
"@rollup/plugin-typescript": "^12.3.0",
|
|
32
|
-
"@types/node": "^
|
|
33
|
-
"prettier": "^3.
|
|
34
|
-
"rollup": "^4.
|
|
35
|
-
"rollup-plugin-delete": "^3.0.2",
|
|
36
|
-
"tslib": "^2.8.1",
|
|
37
|
-
"typescript": "^5.9.3"
|
|
38
|
-
},
|
|
39
|
-
"publishConfig": {
|
|
40
|
-
"access": "public"
|
|
41
|
-
},
|
|
42
|
-
"homepage": "https://khoeckman.github.io/canvasparticles-js/",
|
|
43
|
-
"repository": {
|
|
44
|
-
"type": "git",
|
|
45
|
-
"url": "git+https://github.com/Khoeckman/canvasparticles-js.git"
|
|
46
|
-
},
|
|
47
|
-
"bugs": {
|
|
48
|
-
"url": "https://github.com/Khoeckman/canvasparticles-js/issues"
|
|
49
|
-
},
|
|
50
|
-
"keywords": [
|
|
51
|
-
"front-end",
|
|
52
|
-
"frontend",
|
|
53
|
-
"canvas",
|
|
54
|
-
"particle",
|
|
55
|
-
"particles",
|
|
56
|
-
"jsparticles",
|
|
57
|
-
"js-particles",
|
|
58
|
-
"particles.js",
|
|
59
|
-
"particles-js",
|
|
60
|
-
"xparticles",
|
|
61
|
-
"background",
|
|
62
|
-
"animation",
|
|
63
|
-
"animated",
|
|
64
|
-
"interactive",
|
|
65
|
-
"interaction",
|
|
66
|
-
"web",
|
|
67
|
-
"webdesign",
|
|
68
|
-
"web-design",
|
|
69
|
-
"javascript",
|
|
70
|
-
"js",
|
|
71
|
-
"ecmascript",
|
|
72
|
-
"module",
|
|
73
|
-
"html5",
|
|
74
|
-
"html"
|
|
75
|
-
]
|
|
76
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "canvasparticles-js",
|
|
3
|
+
"version": "4.5.4",
|
|
4
|
+
"description": "In an HTML canvas, a bunch of interactive particles connected with lines when they approach each other.",
|
|
5
|
+
"author": "Khoeckman",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.umd.js",
|
|
9
|
+
"module": "dist/index.mjs",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"require": "./dist/index.cjs",
|
|
15
|
+
"import": "./dist/index.mjs",
|
|
16
|
+
"default": "./dist/index.umd.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"src/",
|
|
21
|
+
"dist/"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "exit 0",
|
|
25
|
+
"build": "rollup -c",
|
|
26
|
+
"prepack": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@rollup/plugin-replace": "^6.0.3",
|
|
30
|
+
"@rollup/plugin-terser": "^1.0.0",
|
|
31
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
32
|
+
"@types/node": "^25.5.0",
|
|
33
|
+
"prettier": "^3.8.1",
|
|
34
|
+
"rollup": "^4.59.0",
|
|
35
|
+
"rollup-plugin-delete": "^3.0.2",
|
|
36
|
+
"tslib": "^2.8.1",
|
|
37
|
+
"typescript": "^5.9.3"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://khoeckman.github.io/canvasparticles-js/",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/Khoeckman/canvasparticles-js.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/Khoeckman/canvasparticles-js/issues"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"front-end",
|
|
52
|
+
"frontend",
|
|
53
|
+
"canvas",
|
|
54
|
+
"particle",
|
|
55
|
+
"particles",
|
|
56
|
+
"jsparticles",
|
|
57
|
+
"js-particles",
|
|
58
|
+
"particles.js",
|
|
59
|
+
"particles-js",
|
|
60
|
+
"xparticles",
|
|
61
|
+
"background",
|
|
62
|
+
"animation",
|
|
63
|
+
"animated",
|
|
64
|
+
"interactive",
|
|
65
|
+
"interaction",
|
|
66
|
+
"web",
|
|
67
|
+
"webdesign",
|
|
68
|
+
"web-design",
|
|
69
|
+
"javascript",
|
|
70
|
+
"js",
|
|
71
|
+
"ecmascript",
|
|
72
|
+
"module",
|
|
73
|
+
"html5",
|
|
74
|
+
"html"
|
|
75
|
+
]
|
|
76
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ function Mulberry32(seed: number) {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
// Mulberry32 is
|
|
26
|
+
// Mulberry32 is x4 faster than Math.random()
|
|
27
27
|
// Benchmark: https://jsbm.dev/muLCWR9RJCbmy
|
|
28
28
|
// Spectral test: /demo/mulberry32.html
|
|
29
29
|
const prng = Mulberry32(Math.random() * 4294967296).next
|
|
@@ -178,11 +178,13 @@ export default class CanvasParticles {
|
|
|
178
178
|
|
|
179
179
|
/** Resize the canvas and update particles accordingly */
|
|
180
180
|
#resizeCanvas(dpr = window.devicePixelRatio || 1) {
|
|
181
|
+
if (dpr < 1) dpr = 1
|
|
182
|
+
|
|
181
183
|
const width = (this.canvas.width = this.canvas.rect.width * dpr)
|
|
182
184
|
const height = (this.canvas.height = this.canvas.rect.height * dpr)
|
|
183
185
|
|
|
184
186
|
// Must be set every time width or height changes because scale is removed
|
|
185
|
-
if (dpr
|
|
187
|
+
if (dpr > 1) this.ctx.scale(dpr, dpr)
|
|
186
188
|
|
|
187
189
|
// Hide the mouse when resizing because it must be outside the viewport to do so
|
|
188
190
|
this.mouseX = Infinity
|
|
@@ -500,12 +502,13 @@ export default class CanvasParticles {
|
|
|
500
502
|
/** Draw the particles on the canvas */
|
|
501
503
|
#renderParticles() {
|
|
502
504
|
const ctx = this.ctx
|
|
505
|
+
const dpr = window.devicePixelRatio || 1
|
|
503
506
|
|
|
504
507
|
for (const p of this.particles) {
|
|
505
508
|
if (!p.isVisible) continue
|
|
506
509
|
|
|
507
510
|
// Draw particles smaller than 1px as a square instead of a circle for performance
|
|
508
|
-
if (p.size > 1) {
|
|
511
|
+
if (p.size > 1 / dpr) {
|
|
509
512
|
// Draw circle
|
|
510
513
|
ctx.beginPath()
|
|
511
514
|
ctx.arc(p.x, p.y, p.size, 0, TWO_PI)
|
|
@@ -774,7 +777,7 @@ export default class CanvasParticles {
|
|
|
774
777
|
|
|
775
778
|
/** Clear the canvas and render the particles and their connections onto the canvas */
|
|
776
779
|
#render() {
|
|
777
|
-
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
|
780
|
+
this.ctx.clearRect(0, 0, this.canvas.rect.width, this.canvas.rect.height)
|
|
778
781
|
|
|
779
782
|
this.ctx.globalAlpha = this.color.alpha
|
|
780
783
|
this.ctx.fillStyle = this.color.hex
|
|
@@ -816,7 +819,7 @@ export default class CanvasParticles {
|
|
|
816
819
|
stop({ auto = false, clear = true }: { auto?: boolean; clear?: boolean } = {}): boolean {
|
|
817
820
|
if (!auto) this.enableAnimating = false
|
|
818
821
|
this.isAnimating = false
|
|
819
|
-
if (clear !== false) this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
|
822
|
+
if (clear !== false) this.ctx.clearRect(0, 0, this.canvas.rect.width, this.canvas.rect.height)
|
|
820
823
|
return true
|
|
821
824
|
}
|
|
822
825
|
|