particle-canvas-pro 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 lebron_shi and Particle Canvas Pro Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
File without changes
@@ -0,0 +1 @@
1
+ "use strict";module.exports=class{constructor(i={}){this.MAX_PARTICLE_NUMBER=800,this.MAX_PARTICLE_SPEED=3,this.MAX_PARTICLE_SIZE=10,this.MAX_LINK_DISTANCE=300,this.MAX_LINE_WIDTH=5,this.MAX_LINE_OPACITY=1,this.MAX_TRAIL_VALUE=1,this.validateOptionsType(i);const t=this.validateAndLimitOptions(i);this.config={canvasContainer:t.canvasContainer||document.body,isBackground:void 0===t.isBackground||t.isBackground,canvasBackgroundColor:t.canvasBackgroundColor||"rgba(10, 10, 25, 1)",particleNumber:t.particleNumber||150,particleSpeed:t.particleSpeed||1,particleSize:t.particleSize||5,particleColor:t.particleColor||"rgba(156, 74, 255, 0.6)",lineWidth:t.lineWidth||1,lineColor:t.lineColor||"#ffffff",lineOpacity:t.lineOpacity||.3,linkDistance:t.linkDistance||120,showLinkLine:void 0===t.showLinkLine||t.showLinkLine,canvasSize:t.canvasSize||[800,600],trailValue:t.trailValue||.2},this.particles=[],this.animationId=null,this.isRunning=!1,this.lastTime=0,this.fps=60,this.fpsInterval=1e3/60,this.then=Date.now(),this.frameCount=0,this.lastFpsUpdate=Date.now(),this.init()}validateOptionsType(i){null!=i&&("object"!=typeof i||Array.isArray(i)?console.warn("Warning: options parameter must be an object. Using default configuration."):(void 0===i.canvasContainer||"string"==typeof i.canvasContainer||i.canvasContainer instanceof HTMLElement||console.warn("Warning: canvasContainer must be a string selector or HTMLElement. Using default value."),void 0!==i.isBackground&&"boolean"!=typeof i.isBackground&&console.warn("Warning: isBackground must be a boolean. Using default value."),void 0!==i.canvasBackgroundColor&&"string"!=typeof i.canvasBackgroundColor&&console.warn("Warning: canvasBackgroundColor must be a string. Using default value."),void 0!==i.particleNumber&&"number"!=typeof i.particleNumber&&console.warn("Warning: particleNumber must be a number. Using default value."),void 0!==i.particleSpeed&&"number"!=typeof i.particleSpeed&&console.warn("Warning: particleSpeed must be a number. Using default value."),void 0!==i.particleSize&&"number"!=typeof i.particleSize&&console.warn("Warning: particleSize must be a number. Using default value."),void 0===i.particleColor||"string"==typeof i.particleColor||Array.isArray(i.particleColor)||console.warn("Warning: particleColor must be a string or array of strings. Using default value."),void 0!==i.lineWidth&&"number"!=typeof i.lineWidth&&console.warn("Warning: lineWidth must be a number. Using default value."),void 0!==i.lineColor&&"string"!=typeof i.lineColor&&console.warn("Warning: lineColor must be a string. Using default value."),void 0!==i.lineOpacity&&"number"!=typeof i.lineOpacity&&console.warn("Warning: lineOpacity must be a number. Using default value."),void 0!==i.linkDistance&&"number"!=typeof i.linkDistance&&console.warn("Warning: linkDistance must be a number. Using default value."),void 0!==i.showLinkLine&&"boolean"!=typeof i.showLinkLine&&console.warn("Warning: showLinkLine must be a boolean. Using default value."),void 0===i.canvasSize||Array.isArray(i.canvasSize)&&2===i.canvasSize.length&&"number"==typeof i.canvasSize[0]&&"number"==typeof i.canvasSize[1]||console.warn("Warning: canvasSize must be an array of two numbers [width, height]. Using default value."),void 0!==i.trailValue&&"number"!=typeof i.trailValue&&console.warn("Warning: trailValue must be a number. Using default value.")))}validateAndLimitOptions(i){const t=Object.assign({},i);return void 0!==i.particleNumber&&(i.particleNumber>this.MAX_PARTICLE_NUMBER?(console.warn(`Warning: particleNumber (${i.particleNumber}) exceeds maximum allowed value (${this.MAX_PARTICLE_NUMBER}). Using maximum value instead.`),t.particleNumber=this.MAX_PARTICLE_NUMBER):i.particleNumber<1&&(console.warn(`Warning: particleNumber (${i.particleNumber}) is below minimum value (1). Using minimum value instead.`),t.particleNumber=1)),void 0!==i.particleSpeed&&(i.particleSpeed>this.MAX_PARTICLE_SPEED?(console.warn(`Warning: particleSpeed (${i.particleSpeed}) exceeds maximum allowed value (${this.MAX_PARTICLE_SPEED}). Using maximum value instead.`),t.particleSpeed=this.MAX_PARTICLE_SPEED):i.particleSpeed<.1&&(console.warn(`Warning: particleSpeed (${i.particleSpeed}) is below minimum value (0.1). Using minimum value instead.`),t.particleSpeed=.1)),void 0!==i.particleSize&&(i.particleSize>this.MAX_PARTICLE_SIZE?(console.warn(`Warning: particleSize (${i.particleSize}) exceeds maximum allowed value (${this.MAX_PARTICLE_SIZE}). Using maximum value instead.`),t.particleSize=this.MAX_PARTICLE_SIZE):i.particleSize<1&&(console.warn(`Warning: particleSize (${i.particleSize}) is below minimum value (1). Using minimum value instead.`),t.particleSize=1)),void 0!==i.linkDistance&&(i.linkDistance>this.MAX_LINK_DISTANCE?(console.warn(`Warning: linkDistance (${i.linkDistance}) exceeds maximum allowed value (${this.MAX_LINK_DISTANCE}). Using maximum value instead.`),t.linkDistance=this.MAX_LINK_DISTANCE):i.linkDistance<10&&(console.warn(`Warning: linkDistance (${i.linkDistance}) is below minimum value (10). Using minimum value instead.`),t.linkDistance=10)),void 0!==i.lineWidth&&(i.lineWidth>this.MAX_LINE_WIDTH?(console.warn(`Warning: lineWidth (${i.lineWidth}) exceeds maximum allowed value (${this.MAX_LINE_WIDTH}). Using maximum value instead.`),t.lineWidth=this.MAX_LINE_WIDTH):i.lineWidth<.1&&(console.warn(`Warning: lineWidth (${i.lineWidth}) is below minimum value (0.1). Using minimum value instead.`),t.lineWidth=.1)),void 0!==i.lineOpacity&&(i.lineOpacity>this.MAX_LINE_OPACITY?(console.warn(`Warning: lineOpacity (${i.lineOpacity}) exceeds maximum allowed value (${this.MAX_LINE_OPACITY}). Using maximum value instead.`),t.lineOpacity=this.MAX_LINE_OPACITY):i.lineOpacity<0&&(console.warn(`Warning: lineOpacity (${i.lineOpacity}) is below minimum value (0). Using minimum value instead.`),t.lineOpacity=0)),void 0!==i.trailValue&&(i.trailValue>this.MAX_TRAIL_VALUE?(console.warn(`Warning: trailValue (${i.trailValue}) exceeds maximum allowed value (${this.MAX_TRAIL_VALUE}). Using maximum value instead.`),t.trailValue=this.MAX_TRAIL_VALUE):i.trailValue<0&&(console.warn(`Warning: trailValue (${i.trailValue}) is below minimum value (0). Using minimum value instead.`),t.trailValue=0)),t}init(){this.canvas=document.createElement("canvas");const i=this.canvas.getContext("2d");if(!i)throw new Error("Could not get 2D context from canvas");if(this.ctx=i,"string"==typeof this.config.canvasContainer){const i=document.querySelector(this.config.canvasContainer);if(!i)throw new Error(`Canvas container not found: ${this.config.canvasContainer}`);this.container=i}else this.container=this.config.canvasContainer;this.container?(this.container.appendChild(this.canvas),this.setupCanvas(),this.createParticles(),this.bindEvents()):console.error("Canvas container not found")}setupCanvas(){if(this.config.isBackground)this.canvas.style.position="fixed",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.width="100%",this.canvas.style.height="100%",this.canvas.style.zIndex="-1",this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight;else{this.canvas.style.display="block";const[i,t]=this.config.canvasSize;this.canvas.width=i,this.canvas.height=t,this.canvas.style.width=i+"px",this.canvas.style.height=t+"px"}this.canvas.style.pointerEvents="none"}createParticles(){this.particles=[];const i=Array.isArray(this.config.particleColor);for(let t=0;t<this.config.particleNumber;t++){let t;if(i){const i=this.config.particleColor;t=i[Math.floor(Math.random()*i.length)]}else t=this.config.particleColor;this.particles.push({x:Math.random()*this.canvas.width,y:Math.random()*this.canvas.height,vx:2*(Math.random()-.5)*this.config.particleSpeed,vy:2*(Math.random()-.5)*this.config.particleSpeed,size:this.config.particleSize,color:t,originalColor:t,pulse:0,pulseSpeed:.05*Math.random()+.02})}}updateParticles(){for(const i of this.particles)i.pulse+=i.pulseSpeed,i.pulse>2*Math.PI&&(i.pulse=0),i.x+=i.vx,i.y+=i.vy,(i.x<0||i.x>this.canvas.width)&&(i.vx*=-1),(i.y<0||i.y>this.canvas.height)&&(i.vy*=-1),i.x=Math.max(0,Math.min(this.canvas.width,i.x)),i.y=Math.max(0,Math.min(this.canvas.height,i.y))}drawParticles(){if(this.config.trailValue>0){let i=this.config.canvasBackgroundColor;if(i.startsWith("#")){const t=parseInt(i.slice(1,3),16),e=parseInt(i.slice(3,5),16),a=parseInt(i.slice(5,7),16);i=`rgba(${t}, ${e}, ${a}, ${this.config.trailValue})`}else if(i.startsWith("rgb("))i=i.replace("rgb(","rgba(").replace(")",`, ${this.config.trailValue})`);else if(i.startsWith("rgba(")){const t=i.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/);if(t){const e=parseFloat(t[4])*this.config.trailValue;i=`rgba(${t[1]}, ${t[2]}, ${t[3]}, ${e})`}}this.ctx.fillStyle=i,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}else this.ctx.fillStyle=this.config.canvasBackgroundColor,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height);if(this.config.showLinkLine)for(let i=0;i<this.particles.length;i++)for(let t=i+1;t<this.particles.length;t++){const e=this.particles[i].x-this.particles[t].x,a=this.particles[i].y-this.particles[t].y,n=Math.sqrt(e*e+a*a);if(n<this.config.linkDistance){const e=this.config.lineOpacity*(1-n/this.config.linkDistance);this.ctx.strokeStyle=this.config.lineColor,this.ctx.globalAlpha=e,this.ctx.lineWidth=this.config.lineWidth,this.ctx.beginPath(),this.ctx.moveTo(this.particles[i].x,this.particles[i].y),this.ctx.lineTo(this.particles[t].x,this.particles[t].y),this.ctx.stroke()}}this.ctx.globalAlpha=1;for(const i of this.particles){const t=i.size*(1+.2*Math.sin(i.pulse));this.ctx.shadowColor=i.color,this.ctx.shadowBlur=10,this.ctx.beginPath(),this.ctx.arc(i.x,i.y,t,0,2*Math.PI),this.ctx.fillStyle=i.color,this.ctx.fill(),this.ctx.shadowBlur=0}}updateFPS(){this.frameCount++;const i=Date.now(),t=i-this.lastFpsUpdate;t>=1e3&&(this.fps=Math.round(1e3*this.frameCount/t),this.frameCount=0,this.lastFpsUpdate=i)}animate(){if(!this.isRunning)return;const i=Date.now(),t=i-this.then;t>this.fpsInterval&&(this.then=i-t%this.fpsInterval,this.updateParticles(),this.drawParticles(),this.updateFPS()),this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.then=Date.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){this.pause(),this.createParticles(),this.start()}resize(){this.config.isBackground&&(this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight),this.reset()}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&this.resize()}),this.canvas.addEventListener("mousemove",i=>{const t=this.canvas.getBoundingClientRect(),e=i.clientX-t.left,a=i.clientY-t.top;for(const i of this.particles){const t=i.x-e,n=i.y-a,s=Math.sqrt(t*t+n*n);if(s<100){const e=(100-s)/100;i.vx+=.01*t*e,i.vy+=.01*n*e}}})}};
@@ -0,0 +1 @@
1
+ class i{constructor(i={}){this.MAX_PARTICLE_NUMBER=800,this.MAX_PARTICLE_SPEED=3,this.MAX_PARTICLE_SIZE=10,this.MAX_LINK_DISTANCE=300,this.MAX_LINE_WIDTH=5,this.MAX_LINE_OPACITY=1,this.MAX_TRAIL_VALUE=1,this.validateOptionsType(i);const t=this.validateAndLimitOptions(i);this.config={canvasContainer:t.canvasContainer||document.body,isBackground:void 0===t.isBackground||t.isBackground,canvasBackgroundColor:t.canvasBackgroundColor||"rgba(10, 10, 25, 1)",particleNumber:t.particleNumber||150,particleSpeed:t.particleSpeed||1,particleSize:t.particleSize||5,particleColor:t.particleColor||"rgba(156, 74, 255, 0.6)",lineWidth:t.lineWidth||1,lineColor:t.lineColor||"#ffffff",lineOpacity:t.lineOpacity||.3,linkDistance:t.linkDistance||120,showLinkLine:void 0===t.showLinkLine||t.showLinkLine,canvasSize:t.canvasSize||[800,600],trailValue:t.trailValue||.2},this.particles=[],this.animationId=null,this.isRunning=!1,this.lastTime=0,this.fps=60,this.fpsInterval=1e3/60,this.then=Date.now(),this.frameCount=0,this.lastFpsUpdate=Date.now(),this.init()}validateOptionsType(i){null!=i&&("object"!=typeof i||Array.isArray(i)?console.warn("Warning: options parameter must be an object. Using default configuration."):(void 0===i.canvasContainer||"string"==typeof i.canvasContainer||i.canvasContainer instanceof HTMLElement||console.warn("Warning: canvasContainer must be a string selector or HTMLElement. Using default value."),void 0!==i.isBackground&&"boolean"!=typeof i.isBackground&&console.warn("Warning: isBackground must be a boolean. Using default value."),void 0!==i.canvasBackgroundColor&&"string"!=typeof i.canvasBackgroundColor&&console.warn("Warning: canvasBackgroundColor must be a string. Using default value."),void 0!==i.particleNumber&&"number"!=typeof i.particleNumber&&console.warn("Warning: particleNumber must be a number. Using default value."),void 0!==i.particleSpeed&&"number"!=typeof i.particleSpeed&&console.warn("Warning: particleSpeed must be a number. Using default value."),void 0!==i.particleSize&&"number"!=typeof i.particleSize&&console.warn("Warning: particleSize must be a number. Using default value."),void 0===i.particleColor||"string"==typeof i.particleColor||Array.isArray(i.particleColor)||console.warn("Warning: particleColor must be a string or array of strings. Using default value."),void 0!==i.lineWidth&&"number"!=typeof i.lineWidth&&console.warn("Warning: lineWidth must be a number. Using default value."),void 0!==i.lineColor&&"string"!=typeof i.lineColor&&console.warn("Warning: lineColor must be a string. Using default value."),void 0!==i.lineOpacity&&"number"!=typeof i.lineOpacity&&console.warn("Warning: lineOpacity must be a number. Using default value."),void 0!==i.linkDistance&&"number"!=typeof i.linkDistance&&console.warn("Warning: linkDistance must be a number. Using default value."),void 0!==i.showLinkLine&&"boolean"!=typeof i.showLinkLine&&console.warn("Warning: showLinkLine must be a boolean. Using default value."),void 0===i.canvasSize||Array.isArray(i.canvasSize)&&2===i.canvasSize.length&&"number"==typeof i.canvasSize[0]&&"number"==typeof i.canvasSize[1]||console.warn("Warning: canvasSize must be an array of two numbers [width, height]. Using default value."),void 0!==i.trailValue&&"number"!=typeof i.trailValue&&console.warn("Warning: trailValue must be a number. Using default value.")))}validateAndLimitOptions(i){const t=Object.assign({},i);return void 0!==i.particleNumber&&(i.particleNumber>this.MAX_PARTICLE_NUMBER?(console.warn(`Warning: particleNumber (${i.particleNumber}) exceeds maximum allowed value (${this.MAX_PARTICLE_NUMBER}). Using maximum value instead.`),t.particleNumber=this.MAX_PARTICLE_NUMBER):i.particleNumber<1&&(console.warn(`Warning: particleNumber (${i.particleNumber}) is below minimum value (1). Using minimum value instead.`),t.particleNumber=1)),void 0!==i.particleSpeed&&(i.particleSpeed>this.MAX_PARTICLE_SPEED?(console.warn(`Warning: particleSpeed (${i.particleSpeed}) exceeds maximum allowed value (${this.MAX_PARTICLE_SPEED}). Using maximum value instead.`),t.particleSpeed=this.MAX_PARTICLE_SPEED):i.particleSpeed<.1&&(console.warn(`Warning: particleSpeed (${i.particleSpeed}) is below minimum value (0.1). Using minimum value instead.`),t.particleSpeed=.1)),void 0!==i.particleSize&&(i.particleSize>this.MAX_PARTICLE_SIZE?(console.warn(`Warning: particleSize (${i.particleSize}) exceeds maximum allowed value (${this.MAX_PARTICLE_SIZE}). Using maximum value instead.`),t.particleSize=this.MAX_PARTICLE_SIZE):i.particleSize<1&&(console.warn(`Warning: particleSize (${i.particleSize}) is below minimum value (1). Using minimum value instead.`),t.particleSize=1)),void 0!==i.linkDistance&&(i.linkDistance>this.MAX_LINK_DISTANCE?(console.warn(`Warning: linkDistance (${i.linkDistance}) exceeds maximum allowed value (${this.MAX_LINK_DISTANCE}). Using maximum value instead.`),t.linkDistance=this.MAX_LINK_DISTANCE):i.linkDistance<10&&(console.warn(`Warning: linkDistance (${i.linkDistance}) is below minimum value (10). Using minimum value instead.`),t.linkDistance=10)),void 0!==i.lineWidth&&(i.lineWidth>this.MAX_LINE_WIDTH?(console.warn(`Warning: lineWidth (${i.lineWidth}) exceeds maximum allowed value (${this.MAX_LINE_WIDTH}). Using maximum value instead.`),t.lineWidth=this.MAX_LINE_WIDTH):i.lineWidth<.1&&(console.warn(`Warning: lineWidth (${i.lineWidth}) is below minimum value (0.1). Using minimum value instead.`),t.lineWidth=.1)),void 0!==i.lineOpacity&&(i.lineOpacity>this.MAX_LINE_OPACITY?(console.warn(`Warning: lineOpacity (${i.lineOpacity}) exceeds maximum allowed value (${this.MAX_LINE_OPACITY}). Using maximum value instead.`),t.lineOpacity=this.MAX_LINE_OPACITY):i.lineOpacity<0&&(console.warn(`Warning: lineOpacity (${i.lineOpacity}) is below minimum value (0). Using minimum value instead.`),t.lineOpacity=0)),void 0!==i.trailValue&&(i.trailValue>this.MAX_TRAIL_VALUE?(console.warn(`Warning: trailValue (${i.trailValue}) exceeds maximum allowed value (${this.MAX_TRAIL_VALUE}). Using maximum value instead.`),t.trailValue=this.MAX_TRAIL_VALUE):i.trailValue<0&&(console.warn(`Warning: trailValue (${i.trailValue}) is below minimum value (0). Using minimum value instead.`),t.trailValue=0)),t}init(){this.canvas=document.createElement("canvas");const i=this.canvas.getContext("2d");if(!i)throw new Error("Could not get 2D context from canvas");if(this.ctx=i,"string"==typeof this.config.canvasContainer){const i=document.querySelector(this.config.canvasContainer);if(!i)throw new Error(`Canvas container not found: ${this.config.canvasContainer}`);this.container=i}else this.container=this.config.canvasContainer;this.container?(this.container.appendChild(this.canvas),this.setupCanvas(),this.createParticles(),this.bindEvents()):console.error("Canvas container not found")}setupCanvas(){if(this.config.isBackground)this.canvas.style.position="fixed",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.width="100%",this.canvas.style.height="100%",this.canvas.style.zIndex="-1",this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight;else{this.canvas.style.display="block";const[i,t]=this.config.canvasSize;this.canvas.width=i,this.canvas.height=t,this.canvas.style.width=i+"px",this.canvas.style.height=t+"px"}this.canvas.style.pointerEvents="none"}createParticles(){this.particles=[];const i=Array.isArray(this.config.particleColor);for(let t=0;t<this.config.particleNumber;t++){let t;if(i){const i=this.config.particleColor;t=i[Math.floor(Math.random()*i.length)]}else t=this.config.particleColor;this.particles.push({x:Math.random()*this.canvas.width,y:Math.random()*this.canvas.height,vx:2*(Math.random()-.5)*this.config.particleSpeed,vy:2*(Math.random()-.5)*this.config.particleSpeed,size:this.config.particleSize,color:t,originalColor:t,pulse:0,pulseSpeed:.05*Math.random()+.02})}}updateParticles(){for(const i of this.particles)i.pulse+=i.pulseSpeed,i.pulse>2*Math.PI&&(i.pulse=0),i.x+=i.vx,i.y+=i.vy,(i.x<0||i.x>this.canvas.width)&&(i.vx*=-1),(i.y<0||i.y>this.canvas.height)&&(i.vy*=-1),i.x=Math.max(0,Math.min(this.canvas.width,i.x)),i.y=Math.max(0,Math.min(this.canvas.height,i.y))}drawParticles(){if(this.config.trailValue>0){let i=this.config.canvasBackgroundColor;if(i.startsWith("#")){const t=parseInt(i.slice(1,3),16),e=parseInt(i.slice(3,5),16),a=parseInt(i.slice(5,7),16);i=`rgba(${t}, ${e}, ${a}, ${this.config.trailValue})`}else if(i.startsWith("rgb("))i=i.replace("rgb(","rgba(").replace(")",`, ${this.config.trailValue})`);else if(i.startsWith("rgba(")){const t=i.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/);if(t){const e=parseFloat(t[4])*this.config.trailValue;i=`rgba(${t[1]}, ${t[2]}, ${t[3]}, ${e})`}}this.ctx.fillStyle=i,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}else this.ctx.fillStyle=this.config.canvasBackgroundColor,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height);if(this.config.showLinkLine)for(let i=0;i<this.particles.length;i++)for(let t=i+1;t<this.particles.length;t++){const e=this.particles[i].x-this.particles[t].x,a=this.particles[i].y-this.particles[t].y,n=Math.sqrt(e*e+a*a);if(n<this.config.linkDistance){const e=this.config.lineOpacity*(1-n/this.config.linkDistance);this.ctx.strokeStyle=this.config.lineColor,this.ctx.globalAlpha=e,this.ctx.lineWidth=this.config.lineWidth,this.ctx.beginPath(),this.ctx.moveTo(this.particles[i].x,this.particles[i].y),this.ctx.lineTo(this.particles[t].x,this.particles[t].y),this.ctx.stroke()}}this.ctx.globalAlpha=1;for(const i of this.particles){const t=i.size*(1+.2*Math.sin(i.pulse));this.ctx.shadowColor=i.color,this.ctx.shadowBlur=10,this.ctx.beginPath(),this.ctx.arc(i.x,i.y,t,0,2*Math.PI),this.ctx.fillStyle=i.color,this.ctx.fill(),this.ctx.shadowBlur=0}}updateFPS(){this.frameCount++;const i=Date.now(),t=i-this.lastFpsUpdate;t>=1e3&&(this.fps=Math.round(1e3*this.frameCount/t),this.frameCount=0,this.lastFpsUpdate=i)}animate(){if(!this.isRunning)return;const i=Date.now(),t=i-this.then;t>this.fpsInterval&&(this.then=i-t%this.fpsInterval,this.updateParticles(),this.drawParticles(),this.updateFPS()),this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.then=Date.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){this.pause(),this.createParticles(),this.start()}resize(){this.config.isBackground&&(this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight),this.reset()}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&this.resize()}),this.canvas.addEventListener("mousemove",i=>{const t=this.canvas.getBoundingClientRect(),e=i.clientX-t.left,a=i.clientY-t.top;for(const i of this.particles){const t=i.x-e,n=i.y-a,s=Math.sqrt(t*t+n*n);if(s<100){const e=(100-s)/100;i.vx+=.01*t*e,i.vy+=.01*n*e}}})}}export{i as default};
package/dist/bundle.js ADDED
@@ -0,0 +1 @@
1
+ var MyBundle=function(){"use strict";return class{constructor(i={}){this.MAX_PARTICLE_NUMBER=800,this.MAX_PARTICLE_SPEED=3,this.MAX_PARTICLE_SIZE=10,this.MAX_LINK_DISTANCE=300,this.MAX_LINE_WIDTH=5,this.MAX_LINE_OPACITY=1,this.MAX_TRAIL_VALUE=1,this.validateOptionsType(i);const t=this.validateAndLimitOptions(i);this.config={canvasContainer:t.canvasContainer||document.body,isBackground:void 0===t.isBackground||t.isBackground,canvasBackgroundColor:t.canvasBackgroundColor||"rgba(10, 10, 25, 1)",particleNumber:t.particleNumber||150,particleSpeed:t.particleSpeed||1,particleSize:t.particleSize||5,particleColor:t.particleColor||"rgba(156, 74, 255, 0.6)",lineWidth:t.lineWidth||1,lineColor:t.lineColor||"#ffffff",lineOpacity:t.lineOpacity||.3,linkDistance:t.linkDistance||120,showLinkLine:void 0===t.showLinkLine||t.showLinkLine,canvasSize:t.canvasSize||[800,600],trailValue:t.trailValue||.2},this.particles=[],this.animationId=null,this.isRunning=!1,this.lastTime=0,this.fps=60,this.fpsInterval=1e3/60,this.then=Date.now(),this.frameCount=0,this.lastFpsUpdate=Date.now(),this.init()}validateOptionsType(i){null!=i&&("object"!=typeof i||Array.isArray(i)?console.warn("Warning: options parameter must be an object. Using default configuration."):(void 0===i.canvasContainer||"string"==typeof i.canvasContainer||i.canvasContainer instanceof HTMLElement||console.warn("Warning: canvasContainer must be a string selector or HTMLElement. Using default value."),void 0!==i.isBackground&&"boolean"!=typeof i.isBackground&&console.warn("Warning: isBackground must be a boolean. Using default value."),void 0!==i.canvasBackgroundColor&&"string"!=typeof i.canvasBackgroundColor&&console.warn("Warning: canvasBackgroundColor must be a string. Using default value."),void 0!==i.particleNumber&&"number"!=typeof i.particleNumber&&console.warn("Warning: particleNumber must be a number. Using default value."),void 0!==i.particleSpeed&&"number"!=typeof i.particleSpeed&&console.warn("Warning: particleSpeed must be a number. Using default value."),void 0!==i.particleSize&&"number"!=typeof i.particleSize&&console.warn("Warning: particleSize must be a number. Using default value."),void 0===i.particleColor||"string"==typeof i.particleColor||Array.isArray(i.particleColor)||console.warn("Warning: particleColor must be a string or array of strings. Using default value."),void 0!==i.lineWidth&&"number"!=typeof i.lineWidth&&console.warn("Warning: lineWidth must be a number. Using default value."),void 0!==i.lineColor&&"string"!=typeof i.lineColor&&console.warn("Warning: lineColor must be a string. Using default value."),void 0!==i.lineOpacity&&"number"!=typeof i.lineOpacity&&console.warn("Warning: lineOpacity must be a number. Using default value."),void 0!==i.linkDistance&&"number"!=typeof i.linkDistance&&console.warn("Warning: linkDistance must be a number. Using default value."),void 0!==i.showLinkLine&&"boolean"!=typeof i.showLinkLine&&console.warn("Warning: showLinkLine must be a boolean. Using default value."),void 0===i.canvasSize||Array.isArray(i.canvasSize)&&2===i.canvasSize.length&&"number"==typeof i.canvasSize[0]&&"number"==typeof i.canvasSize[1]||console.warn("Warning: canvasSize must be an array of two numbers [width, height]. Using default value."),void 0!==i.trailValue&&"number"!=typeof i.trailValue&&console.warn("Warning: trailValue must be a number. Using default value.")))}validateAndLimitOptions(i){const t=Object.assign({},i);return void 0!==i.particleNumber&&(i.particleNumber>this.MAX_PARTICLE_NUMBER?(console.warn(`Warning: particleNumber (${i.particleNumber}) exceeds maximum allowed value (${this.MAX_PARTICLE_NUMBER}). Using maximum value instead.`),t.particleNumber=this.MAX_PARTICLE_NUMBER):i.particleNumber<1&&(console.warn(`Warning: particleNumber (${i.particleNumber}) is below minimum value (1). Using minimum value instead.`),t.particleNumber=1)),void 0!==i.particleSpeed&&(i.particleSpeed>this.MAX_PARTICLE_SPEED?(console.warn(`Warning: particleSpeed (${i.particleSpeed}) exceeds maximum allowed value (${this.MAX_PARTICLE_SPEED}). Using maximum value instead.`),t.particleSpeed=this.MAX_PARTICLE_SPEED):i.particleSpeed<.1&&(console.warn(`Warning: particleSpeed (${i.particleSpeed}) is below minimum value (0.1). Using minimum value instead.`),t.particleSpeed=.1)),void 0!==i.particleSize&&(i.particleSize>this.MAX_PARTICLE_SIZE?(console.warn(`Warning: particleSize (${i.particleSize}) exceeds maximum allowed value (${this.MAX_PARTICLE_SIZE}). Using maximum value instead.`),t.particleSize=this.MAX_PARTICLE_SIZE):i.particleSize<1&&(console.warn(`Warning: particleSize (${i.particleSize}) is below minimum value (1). Using minimum value instead.`),t.particleSize=1)),void 0!==i.linkDistance&&(i.linkDistance>this.MAX_LINK_DISTANCE?(console.warn(`Warning: linkDistance (${i.linkDistance}) exceeds maximum allowed value (${this.MAX_LINK_DISTANCE}). Using maximum value instead.`),t.linkDistance=this.MAX_LINK_DISTANCE):i.linkDistance<10&&(console.warn(`Warning: linkDistance (${i.linkDistance}) is below minimum value (10). Using minimum value instead.`),t.linkDistance=10)),void 0!==i.lineWidth&&(i.lineWidth>this.MAX_LINE_WIDTH?(console.warn(`Warning: lineWidth (${i.lineWidth}) exceeds maximum allowed value (${this.MAX_LINE_WIDTH}). Using maximum value instead.`),t.lineWidth=this.MAX_LINE_WIDTH):i.lineWidth<.1&&(console.warn(`Warning: lineWidth (${i.lineWidth}) is below minimum value (0.1). Using minimum value instead.`),t.lineWidth=.1)),void 0!==i.lineOpacity&&(i.lineOpacity>this.MAX_LINE_OPACITY?(console.warn(`Warning: lineOpacity (${i.lineOpacity}) exceeds maximum allowed value (${this.MAX_LINE_OPACITY}). Using maximum value instead.`),t.lineOpacity=this.MAX_LINE_OPACITY):i.lineOpacity<0&&(console.warn(`Warning: lineOpacity (${i.lineOpacity}) is below minimum value (0). Using minimum value instead.`),t.lineOpacity=0)),void 0!==i.trailValue&&(i.trailValue>this.MAX_TRAIL_VALUE?(console.warn(`Warning: trailValue (${i.trailValue}) exceeds maximum allowed value (${this.MAX_TRAIL_VALUE}). Using maximum value instead.`),t.trailValue=this.MAX_TRAIL_VALUE):i.trailValue<0&&(console.warn(`Warning: trailValue (${i.trailValue}) is below minimum value (0). Using minimum value instead.`),t.trailValue=0)),t}init(){this.canvas=document.createElement("canvas");const i=this.canvas.getContext("2d");if(!i)throw new Error("Could not get 2D context from canvas");if(this.ctx=i,"string"==typeof this.config.canvasContainer){const i=document.querySelector(this.config.canvasContainer);if(!i)throw new Error(`Canvas container not found: ${this.config.canvasContainer}`);this.container=i}else this.container=this.config.canvasContainer;this.container?(this.container.appendChild(this.canvas),this.setupCanvas(),this.createParticles(),this.bindEvents()):console.error("Canvas container not found")}setupCanvas(){if(this.config.isBackground)this.canvas.style.position="fixed",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.width="100%",this.canvas.style.height="100%",this.canvas.style.zIndex="-1",this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight;else{this.canvas.style.display="block";const[i,t]=this.config.canvasSize;this.canvas.width=i,this.canvas.height=t,this.canvas.style.width=i+"px",this.canvas.style.height=t+"px"}this.canvas.style.pointerEvents="none"}createParticles(){this.particles=[];const i=Array.isArray(this.config.particleColor);for(let t=0;t<this.config.particleNumber;t++){let t;if(i){const i=this.config.particleColor;t=i[Math.floor(Math.random()*i.length)]}else t=this.config.particleColor;this.particles.push({x:Math.random()*this.canvas.width,y:Math.random()*this.canvas.height,vx:2*(Math.random()-.5)*this.config.particleSpeed,vy:2*(Math.random()-.5)*this.config.particleSpeed,size:this.config.particleSize,color:t,originalColor:t,pulse:0,pulseSpeed:.05*Math.random()+.02})}}updateParticles(){for(const i of this.particles)i.pulse+=i.pulseSpeed,i.pulse>2*Math.PI&&(i.pulse=0),i.x+=i.vx,i.y+=i.vy,(i.x<0||i.x>this.canvas.width)&&(i.vx*=-1),(i.y<0||i.y>this.canvas.height)&&(i.vy*=-1),i.x=Math.max(0,Math.min(this.canvas.width,i.x)),i.y=Math.max(0,Math.min(this.canvas.height,i.y))}drawParticles(){if(this.config.trailValue>0){let i=this.config.canvasBackgroundColor;if(i.startsWith("#")){const t=parseInt(i.slice(1,3),16),e=parseInt(i.slice(3,5),16),a=parseInt(i.slice(5,7),16);i=`rgba(${t}, ${e}, ${a}, ${this.config.trailValue})`}else if(i.startsWith("rgb("))i=i.replace("rgb(","rgba(").replace(")",`, ${this.config.trailValue})`);else if(i.startsWith("rgba(")){const t=i.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/);if(t){const e=parseFloat(t[4])*this.config.trailValue;i=`rgba(${t[1]}, ${t[2]}, ${t[3]}, ${e})`}}this.ctx.fillStyle=i,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}else this.ctx.fillStyle=this.config.canvasBackgroundColor,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height);if(this.config.showLinkLine)for(let i=0;i<this.particles.length;i++)for(let t=i+1;t<this.particles.length;t++){const e=this.particles[i].x-this.particles[t].x,a=this.particles[i].y-this.particles[t].y,n=Math.sqrt(e*e+a*a);if(n<this.config.linkDistance){const e=this.config.lineOpacity*(1-n/this.config.linkDistance);this.ctx.strokeStyle=this.config.lineColor,this.ctx.globalAlpha=e,this.ctx.lineWidth=this.config.lineWidth,this.ctx.beginPath(),this.ctx.moveTo(this.particles[i].x,this.particles[i].y),this.ctx.lineTo(this.particles[t].x,this.particles[t].y),this.ctx.stroke()}}this.ctx.globalAlpha=1;for(const i of this.particles){const t=i.size*(1+.2*Math.sin(i.pulse));this.ctx.shadowColor=i.color,this.ctx.shadowBlur=10,this.ctx.beginPath(),this.ctx.arc(i.x,i.y,t,0,2*Math.PI),this.ctx.fillStyle=i.color,this.ctx.fill(),this.ctx.shadowBlur=0}}updateFPS(){this.frameCount++;const i=Date.now(),t=i-this.lastFpsUpdate;t>=1e3&&(this.fps=Math.round(1e3*this.frameCount/t),this.frameCount=0,this.lastFpsUpdate=i)}animate(){if(!this.isRunning)return;const i=Date.now(),t=i-this.then;t>this.fpsInterval&&(this.then=i-t%this.fpsInterval,this.updateParticles(),this.drawParticles(),this.updateFPS()),this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.then=Date.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){this.pause(),this.createParticles(),this.start()}resize(){this.config.isBackground&&(this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight),this.reset()}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&this.resize()}),this.canvas.addEventListener("mousemove",i=>{const t=this.canvas.getBoundingClientRect(),e=i.clientX-t.left,a=i.clientY-t.top;for(const i of this.particles){const t=i.x-e,n=i.y-a,s=Math.sqrt(t*t+n*n);if(s<100){const e=(100-s)/100;i.vx+=.01*t*e,i.vy+=.01*n*e}}})}}}();
@@ -0,0 +1,106 @@
1
+ /**
2
+ * 高性能粒子系统
3
+ * 使用Canvas实现可配置的粒子动画效果,支持背景模式和内嵌模式
4
+ */
5
+ import { ParticleCanvasOptions } from './types';
6
+ declare class ParticleCanvas {
7
+ private config;
8
+ private particles;
9
+ private animationId;
10
+ private isRunning;
11
+ private lastTime;
12
+ private fps;
13
+ private fpsInterval;
14
+ private then;
15
+ private frameCount;
16
+ private lastFpsUpdate;
17
+ private canvas;
18
+ private ctx;
19
+ private container;
20
+ private readonly MAX_PARTICLE_NUMBER;
21
+ private readonly MAX_PARTICLE_SPEED;
22
+ private readonly MAX_PARTICLE_SIZE;
23
+ private readonly MAX_LINK_DISTANCE;
24
+ private readonly MAX_LINE_WIDTH;
25
+ private readonly MAX_LINE_OPACITY;
26
+ private readonly MAX_TRAIL_VALUE;
27
+ /**
28
+ * 初始化配置
29
+ * @param {ParticleCanvasOptions} options - 配置对象
30
+ */
31
+ constructor(options?: ParticleCanvasOptions);
32
+ /**
33
+ * 验证配置选项类型
34
+ * @param options 用户提供的配置选项
35
+ */
36
+ private validateOptionsType;
37
+ /**
38
+ * 验证并限制配置选项,确保参数在合理范围内
39
+ * @param options 用户提供的配置选项
40
+ * @returns 验证后的配置选项
41
+ */
42
+ private validateAndLimitOptions;
43
+ /**
44
+ * 初始化粒子系统
45
+ * 创建画布、设置容器、创建粒子、绑定事件
46
+ */
47
+ private init;
48
+ /**
49
+ * 设置画布样式和尺寸
50
+ * 根据配置决定是背景模式还是内嵌模式
51
+ */
52
+ private setupCanvas;
53
+ /**
54
+ * 创建粒子数组
55
+ * 根据配置生成指定数量的粒子
56
+ */
57
+ private createParticles;
58
+ /**
59
+ * 更新粒子状态
60
+ * 计算每个粒子的新位置和状态
61
+ */
62
+ private updateParticles;
63
+ /**
64
+ * 绘制粒子和连线
65
+ * 在画布上渲染粒子系统
66
+ */
67
+ private drawParticles;
68
+ /**
69
+ * 更新FPS计数器
70
+ * 计算并更新当前帧率
71
+ */
72
+ private updateFPS;
73
+ /**
74
+ * 动画循环
75
+ * 使用requestAnimationFrame实现平滑动画
76
+ */
77
+ private animate;
78
+ /**
79
+ * 开始粒子动画
80
+ */
81
+ start(): void;
82
+ /**
83
+ * 暂停粒子动画
84
+ */
85
+ pause(): void;
86
+ /**
87
+ * 重置粒子系统
88
+ * 重新创建粒子并开始动画
89
+ */
90
+ reset(): void;
91
+ /**
92
+ * 调整画布尺寸
93
+ * 主要用于响应窗口大小变化
94
+ */
95
+ resize(): void;
96
+ /**
97
+ * 销毁粒子系统
98
+ * 停止动画并移除画布
99
+ */
100
+ destroy(): void;
101
+ /**
102
+ * 绑定事件监听器
103
+ */
104
+ private bindEvents;
105
+ }
106
+ export default ParticleCanvas;
@@ -0,0 +1,43 @@
1
+ export interface Particle {
2
+ x: number;
3
+ y: number;
4
+ vx: number;
5
+ vy: number;
6
+ size: number;
7
+ color: string;
8
+ originalColor: string;
9
+ pulse: number;
10
+ pulseSpeed: number;
11
+ }
12
+ export interface ParticleCanvasOptions {
13
+ canvasContainer?: HTMLElement | string;
14
+ isBackground?: boolean;
15
+ canvasBackgroundColor?: string;
16
+ particleNumber?: number;
17
+ particleSpeed?: number;
18
+ particleSize?: number;
19
+ particleColor?: string | string[];
20
+ lineWidth?: number;
21
+ lineColor?: string;
22
+ lineOpacity?: number;
23
+ linkDistance?: number;
24
+ showLinkLine?: boolean;
25
+ canvasSize?: [number, number];
26
+ trailValue?: number;
27
+ }
28
+ export interface ParticleCanvasConfig {
29
+ canvasContainer: HTMLElement | string;
30
+ isBackground: boolean;
31
+ canvasBackgroundColor: string;
32
+ particleNumber: number;
33
+ particleSpeed: number;
34
+ particleSize: number;
35
+ particleColor: string | string[];
36
+ lineWidth: number;
37
+ lineColor: string;
38
+ lineOpacity: number;
39
+ linkDistance: number;
40
+ showLinkLine: boolean;
41
+ canvasSize: [number, number];
42
+ trailValue: number;
43
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "particle-canvas-pro",
3
+ "version": "1.0.0",
4
+ "description": "🚀 高性能Canvas粒子动画库 - 使用requestAnimationFrame实现流畅的粒子效果,支持全屏背景和自定义画布模式,提供丰富的配置选项和炫酷的视觉效果",
5
+ "main": "dist/bundle.cjs.js",
6
+ "module": "dist/bundle.esm.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/types/index.d.ts",
11
+ "default": "./dist/bundle.esm.js"
12
+ },
13
+ "require": {
14
+ "types": "./dist/types/index.d.ts",
15
+ "default": "./dist/bundle.cjs.js"
16
+ },
17
+ "default": "./dist/bundle.esm.js"
18
+ }
19
+ },
20
+ "types": "dist/types/index.d.ts",
21
+ "unpkg": "dist/bundle.js",
22
+ "type": "module",
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "rollup -c --bundleConfigAsCjs",
28
+ "watch": "rollup -c -w --bundleConfigAsCjs",
29
+ "dev": "serve dist"
30
+ },
31
+ "keywords": [
32
+ "particle",
33
+ "canvas",
34
+ "animation",
35
+ "particle-system",
36
+ "requestanimationframe",
37
+ "javascript-animation",
38
+ "web-animation",
39
+ "fps"
40
+ ],
41
+ "author": "lebron_shi",
42
+ "license": "MIT",
43
+ "devDependencies": {
44
+ "@rollup/plugin-typescript": "^11.1.6",
45
+ "rollup": "^4.57.1",
46
+ "typescript": "^5.4.5",
47
+ "tslib": "^2.6.2",
48
+ "rollup-plugin-terser": "^7.0.2",
49
+ "serve": "^14.2.5"
50
+ }
51
+ }