particle-canvas-pro 1.2.6 → 1.3.1

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 CHANGED
@@ -77,21 +77,22 @@ particleSystem.start();
77
77
  # 参数配置
78
78
 
79
79
  | 参数名 | 说明 | 类型 | 取值范围 | 默认值 |
80
- |------------------------|--------------------------------------|--------------------------|-----------------------------|---------------------------|
81
- | canvasContainer | 画布容器元素或选择器 | `string` / `HTMLElement` | - | `document.body` |
80
+ |------------------------|---------------------------------------|--------------------------|-----------------------------|---------------------------|
81
+ | canvasContainer | 画布容器元素或选择器 | `string` / `HTMLElement` | - | `document.body` |
82
+ | canvasBackgroundColor | 画布背景颜色 | `string` | - | `rgb(10, 10, 25)` |
83
+ | canvasSize | 画布尺寸(非背景模式) | `[number, number]` | - | [800, 600] |
82
84
  | isBackground | 是否作为页面背景 | `boolean` | `true` / `false` | `true` |
83
- | canvasBackgroundColor | 画布背景颜色 | `string` | - | `rgba(10, 10, 25, 1)` |
84
85
  | particleNumber | 粒子数量 | `number` | 1-800 | 150 |
85
- | particleSpeed | 粒子运动速度 | `number` | 0.1-3 | 1 |
86
+ | particleSpeed | 粒子运动速度 | `number` | 0-3 | 1 |
86
87
  | particleSize | 粒子大小(像素) | `number` | 1-10 | 5 |
87
88
  | particleColor | 粒子颜色(单色或多色) | `string` / `string[]` | - | `rgba(156, 74, 255, 0.6)` |
88
- | lineWidth | 连线宽度(像素) | `number` | 0.1-5 | 1 |
89
+ | showTrail | 是否显示粒子轨迹效果 | `boolean` | `true` / `false` | `true` |
90
+ | trailIntensity | 粒子轨迹效果强度 | `number` | 0-5 | 2 |
91
+ | showLine | 是否显示粒子连线 | `boolean` | `true` / `false` | `true` |
92
+ | lineWidth | 连线宽度(像素) | `number` | 0-5 | 1 |
89
93
  | lineColor | 连线颜色 | `string` | - | `#ffffff` |
90
94
  | lineOpacity | 连线透明度 | `number` | 0-1 | 0.3 |
91
95
  | linkDistance | 连线距离(像素) | `number` | 10-300 | 120 |
92
- | showLinkLine | 是否显示连线 | `boolean` | `true` / `false` | `true` |
93
- | canvasSize | 画布尺寸(非背景模式) | `[number, number]` | - | [800, 600] |
94
- | trailValue | 轨迹效果强度 | `number` | 0-1 | 0.2 |
95
96
 
96
97
  <br>
97
98
 
@@ -1 +1 @@
1
- "use strict";const i=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;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.resizeTimer=null,this.wasRunningBeforeHide=!1,this.lastFrameTime=performance.now(),this.init()}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(i){const t=i/16.67;for(const i of this.particles)i.pulse+=i.pulseSpeed*t,i.pulse>2*Math.PI&&(i.pulse=0),i.x+=i.vx*t,i.y+=i.vy*t,(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,s=Math.sqrt(e*e+a*a);if(s<this.config.linkDistance){const e=this.config.lineOpacity*(1-s/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=performance.now(),t=i-this.lastFrameTime,e=Math.min(Math.max(t,1),100);this.updateParticles(e),this.drawParticles(),this.updateFPS(),this.lastFrameTime=i,this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){const i=this.isRunning;i&&this.pause(),this.createParticles(),i?this.start():this.drawParticles()}resize(){if(this.config.isBackground){const i=this.canvas.width,t=this.canvas.height,e=window.innerWidth,a=window.innerHeight;if(this.canvas.width=e,this.canvas.height=a,this.particles.length>0){const s=e/i,n=a/t;for(const i of this.particles)i.x*=s,i.y*=n,i.x=Math.max(0,Math.min(e,i.x)),i.y=Math.max(0,Math.min(a,i.y)),(i.x<=0||i.x>=e)&&(i.vx*=-1),(i.y<=0||i.y>=a)&&(i.vy*=-1);this.drawParticles()}else this.createParticles(),this.drawParticles()}}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&(this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.resize()},150))}),document.addEventListener("visibilitychange",()=>{document.hidden?(this.wasRunningBeforeHide=this.isRunning,this.isRunning&&this.pause()):(this.wasRunningBeforeHide&&this.start(),this.wasRunningBeforeHide=!1)})}};module.exports=i;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});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.MAX_PARTICLE_BLUR=5,this.MAX_TRAIL_INTENSITY=5;const t=this.validateAndLimitOptions(i);this.config={canvasContainer:t.canvasContainer||document.body,isBackground:void 0===t.isBackground||t.isBackground,canvasBackgroundColor:t.canvasBackgroundColor||"rgb(10, 10, 25)",particleNumber:t.particleNumber||150,particleSpeed:t.particleSpeed||1,particleSize:t.particleSize||5,particleColor:t.particleColor||"rgba(156, 74, 255, 0.6)",particleBlur:void 0!==t.particleBlur?t.particleBlur:2,lineWidth:t.lineWidth||1,lineColor:t.lineColor||"#ffffff",lineOpacity:t.lineOpacity||.3,linkDistance:t.linkDistance||120,showLine:void 0===t.showLine||t.showLine,canvasSize:t.canvasSize||[800,600],showTrail:void 0===t.showTrail||t.showTrail,trailIntensity:t.trailIntensity||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.resizeTimer=null,this.wasRunningBeforeHide=!1,this.lastFrameTime=performance.now(),this.init()}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 default value instead.`),t.particleNumber=150)),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<0&&(console.warn(`Warning: particleSpeed (${i.particleSpeed}) is below minimum value (0). Using default 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 default value instead.`),t.particleSize=3)),void 0!==i.particleBlur&&(i.particleBlur>this.MAX_PARTICLE_BLUR?(console.warn(`Warning: particleBlur (${i.particleBlur}) exceeds maximum allowed value (${this.MAX_PARTICLE_BLUR}). Using maximum value instead.`),t.particleBlur=this.MAX_PARTICLE_BLUR):i.particleBlur<0&&(console.warn(`Warning: particleBlur (${i.particleBlur}) is below minimum value (0). Using default value instead.`),t.particleBlur=2)),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 default value instead.`),t.linkDistance=120)),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<0&&(console.warn(`Warning: lineWidth (${i.lineWidth}) is below minimum value (0). Using default 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 default value instead.`),t.lineOpacity=.3)),void 0!==i.trailIntensity&&(i.trailIntensity>this.MAX_TRAIL_INTENSITY?(console.warn(`Warning: trailIntensity (${i.trailIntensity}) exceeds maximum allowed value (${this.MAX_TRAIL_INTENSITY}). Using maximum value instead.`),t.trailIntensity=this.MAX_TRAIL_INTENSITY):i.trailIntensity<1&&(console.warn(`Warning: trailIntensity (${i.trailIntensity}) is below minimum value (1). Using default value instead.`),t.trailIntensity=2)),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,trailPositions:[]})}}updateParticles(i){const t=i/16.67;for(const i of this.particles)i.pulse+=i.pulseSpeed*t,i.pulse>2*Math.PI&&(i.pulse=0),this.config.showTrail&&(i.trailPositions.unshift({x:i.x,y:i.y}),i.trailPositions.length>10*this.config.trailIntensity&&(i.trailPositions.length=10*this.config.trailIntensity)),i.x+=i.vx*t,i.y+=i.vy*t,(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))}drawTrailEffect(){if(this.config.showTrail){this.ctx.save();for(const i of this.particles){if(i.trailPositions.length<2)continue;this.ctx.beginPath(),this.ctx.moveTo(i.trailPositions[0].x,i.trailPositions[0].y);for(let t=1;t<i.trailPositions.length;t++)this.ctx.lineTo(i.trailPositions[t].x,i.trailPositions[t].y);const t=1.2*i.size;this.ctx.lineWidth=t,this.ctx.lineCap="round",this.ctx.lineJoin="round";const s=i.trailPositions[0],e=i.trailPositions[i.trailPositions.length-1],a=this.ctx.createLinearGradient(s.x,s.y,e.x,e.y),n=this.parseColor(i.color),r=.35;a.addColorStop(0,`rgba(${n.r}, ${n.g}, ${n.b}, ${r})`),a.addColorStop(.3,`rgba(${n.r}, ${n.g}, ${n.b}, ${.6*r})`),a.addColorStop(.7,`rgba(${n.r}, ${n.g}, ${n.b}, ${.2*r})`),a.addColorStop(1,`rgba(${n.r}, ${n.g}, ${n.b}, 0)`),this.ctx.strokeStyle=a,this.ctx.stroke()}this.ctx.restore()}}parseColor(i){if(i.startsWith("rgba")){const t=i.match(/rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)/);if(t)return{r:parseInt(t[1]),g:parseInt(t[2]),b:parseInt(t[3]),a:parseFloat(t[4])}}else if(i.startsWith("rgb")){const t=i.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/);if(t)return{r:parseInt(t[1]),g:parseInt(t[2]),b:parseInt(t[3])}}else if(i.startsWith("#")){let t,s,e,a=i.replace("#","");if(3===a.length)t=parseInt(a[0]+a[0],16),s=parseInt(a[1]+a[1],16),e=parseInt(a[2]+a[2],16);else{if(6!==a.length)return{r:255,g:255,b:255};t=parseInt(a.substring(0,2),16),s=parseInt(a.substring(2,4),16),e=parseInt(a.substring(4,6),16)}return{r:t,g:s,b:e}}return{r:255,g:255,b:255}}drawParticles(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);let i=this.config.canvasBackgroundColor;if(i.startsWith("rgba")){const t=i.match(/rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)/);if(t){const s=t[1],e=t[2],a=t[3];parseFloat(t[4])<1&&(i=`rgb(${s}, ${e}, ${a})`)}}if(this.ctx.fillStyle=i,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height),this.drawTrailEffect(),this.config.showLine)for(let i=0;i<this.particles.length;i++)for(let t=i+1;t<this.particles.length;t++){const s=this.particles[i].x-this.particles[t].x,e=this.particles[i].y-this.particles[t].y,a=Math.sqrt(s*s+e*e);if(a<this.config.linkDistance){const s=this.config.lineOpacity*(1-a/this.config.linkDistance);this.ctx.strokeStyle=this.config.lineColor,this.ctx.globalAlpha=s,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.config.particleBlur>0&&(this.ctx.shadowColor=i.color,this.ctx.shadowBlur=4*this.config.particleBlur),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=performance.now(),t=i-this.lastFrameTime,s=Math.min(Math.max(t,1),100);this.updateParticles(s),this.drawParticles(),this.updateFPS(),this.lastFrameTime=i,this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){const i=this.isRunning;i&&this.pause(),this.createParticles(),i?this.start():this.drawParticles()}resize(){if(this.config.isBackground){const i=this.canvas.width,t=this.canvas.height,s=window.innerWidth,e=window.innerHeight;if(this.canvas.width=s,this.canvas.height=e,this.particles.length>0){const a=s/i,n=e/t;for(const i of this.particles)if(i.x*=a,i.y*=n,i.x=Math.max(0,Math.min(s,i.x)),i.y=Math.max(0,Math.min(e,i.y)),(i.x<=0||i.x>=s)&&(i.vx*=-1),(i.y<=0||i.y>=e)&&(i.vy*=-1),this.config.showTrail)for(let t=0;t<i.trailPositions.length;t++){const r=i.trailPositions[t];r.x*=a,r.y*=n,r.x=Math.max(0,Math.min(s,r.x)),r.y=Math.max(0,Math.min(e,r.y))}this.drawParticles()}else this.createParticles(),this.drawParticles()}}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&(this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.resize()},150))}),document.addEventListener("visibilitychange",()=>{document.hidden?(this.wasRunningBeforeHide=this.isRunning,this.isRunning&&this.pause()):(this.wasRunningBeforeHide&&this.start(),this.wasRunningBeforeHide=!1)})}}const t=i;exports.ParticleCanvas=i,exports.default=t;
@@ -1 +1 @@
1
- const i=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;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.resizeTimer=null,this.wasRunningBeforeHide=!1,this.lastFrameTime=performance.now(),this.init()}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(i){const t=i/16.67;for(const i of this.particles)i.pulse+=i.pulseSpeed*t,i.pulse>2*Math.PI&&(i.pulse=0),i.x+=i.vx*t,i.y+=i.vy*t,(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,s=Math.sqrt(e*e+a*a);if(s<this.config.linkDistance){const e=this.config.lineOpacity*(1-s/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=performance.now(),t=i-this.lastFrameTime,e=Math.min(Math.max(t,1),100);this.updateParticles(e),this.drawParticles(),this.updateFPS(),this.lastFrameTime=i,this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){const i=this.isRunning;i&&this.pause(),this.createParticles(),i?this.start():this.drawParticles()}resize(){if(this.config.isBackground){const i=this.canvas.width,t=this.canvas.height,e=window.innerWidth,a=window.innerHeight;if(this.canvas.width=e,this.canvas.height=a,this.particles.length>0){const s=e/i,n=a/t;for(const i of this.particles)i.x*=s,i.y*=n,i.x=Math.max(0,Math.min(e,i.x)),i.y=Math.max(0,Math.min(a,i.y)),(i.x<=0||i.x>=e)&&(i.vx*=-1),(i.y<=0||i.y>=a)&&(i.vy*=-1);this.drawParticles()}else this.createParticles(),this.drawParticles()}}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&(this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.resize()},150))}),document.addEventListener("visibilitychange",()=>{document.hidden?(this.wasRunningBeforeHide=this.isRunning,this.isRunning&&this.pause()):(this.wasRunningBeforeHide&&this.start(),this.wasRunningBeforeHide=!1)})}};export{i as default};
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.MAX_PARTICLE_BLUR=5,this.MAX_TRAIL_INTENSITY=5;const t=this.validateAndLimitOptions(i);this.config={canvasContainer:t.canvasContainer||document.body,isBackground:void 0===t.isBackground||t.isBackground,canvasBackgroundColor:t.canvasBackgroundColor||"rgb(10, 10, 25)",particleNumber:t.particleNumber||150,particleSpeed:t.particleSpeed||1,particleSize:t.particleSize||5,particleColor:t.particleColor||"rgba(156, 74, 255, 0.6)",particleBlur:void 0!==t.particleBlur?t.particleBlur:2,lineWidth:t.lineWidth||1,lineColor:t.lineColor||"#ffffff",lineOpacity:t.lineOpacity||.3,linkDistance:t.linkDistance||120,showLine:void 0===t.showLine||t.showLine,canvasSize:t.canvasSize||[800,600],showTrail:void 0===t.showTrail||t.showTrail,trailIntensity:t.trailIntensity||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.resizeTimer=null,this.wasRunningBeforeHide=!1,this.lastFrameTime=performance.now(),this.init()}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 default value instead.`),t.particleNumber=150)),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<0&&(console.warn(`Warning: particleSpeed (${i.particleSpeed}) is below minimum value (0). Using default 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 default value instead.`),t.particleSize=3)),void 0!==i.particleBlur&&(i.particleBlur>this.MAX_PARTICLE_BLUR?(console.warn(`Warning: particleBlur (${i.particleBlur}) exceeds maximum allowed value (${this.MAX_PARTICLE_BLUR}). Using maximum value instead.`),t.particleBlur=this.MAX_PARTICLE_BLUR):i.particleBlur<0&&(console.warn(`Warning: particleBlur (${i.particleBlur}) is below minimum value (0). Using default value instead.`),t.particleBlur=2)),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 default value instead.`),t.linkDistance=120)),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<0&&(console.warn(`Warning: lineWidth (${i.lineWidth}) is below minimum value (0). Using default 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 default value instead.`),t.lineOpacity=.3)),void 0!==i.trailIntensity&&(i.trailIntensity>this.MAX_TRAIL_INTENSITY?(console.warn(`Warning: trailIntensity (${i.trailIntensity}) exceeds maximum allowed value (${this.MAX_TRAIL_INTENSITY}). Using maximum value instead.`),t.trailIntensity=this.MAX_TRAIL_INTENSITY):i.trailIntensity<1&&(console.warn(`Warning: trailIntensity (${i.trailIntensity}) is below minimum value (1). Using default value instead.`),t.trailIntensity=2)),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,trailPositions:[]})}}updateParticles(i){const t=i/16.67;for(const i of this.particles)i.pulse+=i.pulseSpeed*t,i.pulse>2*Math.PI&&(i.pulse=0),this.config.showTrail&&(i.trailPositions.unshift({x:i.x,y:i.y}),i.trailPositions.length>10*this.config.trailIntensity&&(i.trailPositions.length=10*this.config.trailIntensity)),i.x+=i.vx*t,i.y+=i.vy*t,(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))}drawTrailEffect(){if(this.config.showTrail){this.ctx.save();for(const i of this.particles){if(i.trailPositions.length<2)continue;this.ctx.beginPath(),this.ctx.moveTo(i.trailPositions[0].x,i.trailPositions[0].y);for(let t=1;t<i.trailPositions.length;t++)this.ctx.lineTo(i.trailPositions[t].x,i.trailPositions[t].y);const t=1.2*i.size;this.ctx.lineWidth=t,this.ctx.lineCap="round",this.ctx.lineJoin="round";const s=i.trailPositions[0],e=i.trailPositions[i.trailPositions.length-1],a=this.ctx.createLinearGradient(s.x,s.y,e.x,e.y),n=this.parseColor(i.color),r=.35;a.addColorStop(0,`rgba(${n.r}, ${n.g}, ${n.b}, ${r})`),a.addColorStop(.3,`rgba(${n.r}, ${n.g}, ${n.b}, ${.6*r})`),a.addColorStop(.7,`rgba(${n.r}, ${n.g}, ${n.b}, ${.2*r})`),a.addColorStop(1,`rgba(${n.r}, ${n.g}, ${n.b}, 0)`),this.ctx.strokeStyle=a,this.ctx.stroke()}this.ctx.restore()}}parseColor(i){if(i.startsWith("rgba")){const t=i.match(/rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)/);if(t)return{r:parseInt(t[1]),g:parseInt(t[2]),b:parseInt(t[3]),a:parseFloat(t[4])}}else if(i.startsWith("rgb")){const t=i.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/);if(t)return{r:parseInt(t[1]),g:parseInt(t[2]),b:parseInt(t[3])}}else if(i.startsWith("#")){let t,s,e,a=i.replace("#","");if(3===a.length)t=parseInt(a[0]+a[0],16),s=parseInt(a[1]+a[1],16),e=parseInt(a[2]+a[2],16);else{if(6!==a.length)return{r:255,g:255,b:255};t=parseInt(a.substring(0,2),16),s=parseInt(a.substring(2,4),16),e=parseInt(a.substring(4,6),16)}return{r:t,g:s,b:e}}return{r:255,g:255,b:255}}drawParticles(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);let i=this.config.canvasBackgroundColor;if(i.startsWith("rgba")){const t=i.match(/rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)/);if(t){const s=t[1],e=t[2],a=t[3];parseFloat(t[4])<1&&(i=`rgb(${s}, ${e}, ${a})`)}}if(this.ctx.fillStyle=i,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height),this.drawTrailEffect(),this.config.showLine)for(let i=0;i<this.particles.length;i++)for(let t=i+1;t<this.particles.length;t++){const s=this.particles[i].x-this.particles[t].x,e=this.particles[i].y-this.particles[t].y,a=Math.sqrt(s*s+e*e);if(a<this.config.linkDistance){const s=this.config.lineOpacity*(1-a/this.config.linkDistance);this.ctx.strokeStyle=this.config.lineColor,this.ctx.globalAlpha=s,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.config.particleBlur>0&&(this.ctx.shadowColor=i.color,this.ctx.shadowBlur=4*this.config.particleBlur),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=performance.now(),t=i-this.lastFrameTime,s=Math.min(Math.max(t,1),100);this.updateParticles(s),this.drawParticles(),this.updateFPS(),this.lastFrameTime=i,this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){const i=this.isRunning;i&&this.pause(),this.createParticles(),i?this.start():this.drawParticles()}resize(){if(this.config.isBackground){const i=this.canvas.width,t=this.canvas.height,s=window.innerWidth,e=window.innerHeight;if(this.canvas.width=s,this.canvas.height=e,this.particles.length>0){const a=s/i,n=e/t;for(const i of this.particles)if(i.x*=a,i.y*=n,i.x=Math.max(0,Math.min(s,i.x)),i.y=Math.max(0,Math.min(e,i.y)),(i.x<=0||i.x>=s)&&(i.vx*=-1),(i.y<=0||i.y>=e)&&(i.vy*=-1),this.config.showTrail)for(let t=0;t<i.trailPositions.length;t++){const r=i.trailPositions[t];r.x*=a,r.y*=n,r.x=Math.max(0,Math.min(s,r.x)),r.y=Math.max(0,Math.min(e,r.y))}this.drawParticles()}else this.createParticles(),this.drawParticles()}}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&(this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.resize()},150))}),document.addEventListener("visibilitychange",()=>{document.hidden?(this.wasRunningBeforeHide=this.isRunning,this.isRunning&&this.pause()):(this.wasRunningBeforeHide&&this.start(),this.wasRunningBeforeHide=!1)})}}const t=i;export{i as ParticleCanvas,t as default};
package/dist/bundle.js CHANGED
@@ -1 +1 @@
1
- var ParticleCanvasPro=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;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.resizeTimer=null,this.wasRunningBeforeHide=!1,this.lastFrameTime=performance.now(),this.init()}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(i){const t=i/16.67;for(const i of this.particles)i.pulse+=i.pulseSpeed*t,i.pulse>2*Math.PI&&(i.pulse=0),i.x+=i.vx*t,i.y+=i.vy*t,(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,s=Math.sqrt(e*e+a*a);if(s<this.config.linkDistance){const e=this.config.lineOpacity*(1-s/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=performance.now(),t=i-this.lastFrameTime,e=Math.min(Math.max(t,1),100);this.updateParticles(e),this.drawParticles(),this.updateFPS(),this.lastFrameTime=i,this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){const i=this.isRunning;i&&this.pause(),this.createParticles(),i?this.start():this.drawParticles()}resize(){if(this.config.isBackground){const i=this.canvas.width,t=this.canvas.height,e=window.innerWidth,a=window.innerHeight;if(this.canvas.width=e,this.canvas.height=a,this.particles.length>0){const s=e/i,n=a/t;for(const i of this.particles)i.x*=s,i.y*=n,i.x=Math.max(0,Math.min(e,i.x)),i.y=Math.max(0,Math.min(a,i.y)),(i.x<=0||i.x>=e)&&(i.vx*=-1),(i.y<=0||i.y>=a)&&(i.vy*=-1);this.drawParticles()}else this.createParticles(),this.drawParticles()}}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&(this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.resize()},150))}),document.addEventListener("visibilitychange",()=>{document.hidden?(this.wasRunningBeforeHide=this.isRunning,this.isRunning&&this.pause()):(this.wasRunningBeforeHide&&this.start(),this.wasRunningBeforeHide=!1)})}}}();
1
+ var ParticleCanvasPro=function(i){"use strict";class t{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.MAX_PARTICLE_BLUR=5,this.MAX_TRAIL_INTENSITY=5;const t=this.validateAndLimitOptions(i);this.config={canvasContainer:t.canvasContainer||document.body,isBackground:void 0===t.isBackground||t.isBackground,canvasBackgroundColor:t.canvasBackgroundColor||"rgb(10, 10, 25)",particleNumber:t.particleNumber||150,particleSpeed:t.particleSpeed||1,particleSize:t.particleSize||5,particleColor:t.particleColor||"rgba(156, 74, 255, 0.6)",particleBlur:void 0!==t.particleBlur?t.particleBlur:2,lineWidth:t.lineWidth||1,lineColor:t.lineColor||"#ffffff",lineOpacity:t.lineOpacity||.3,linkDistance:t.linkDistance||120,showLine:void 0===t.showLine||t.showLine,canvasSize:t.canvasSize||[800,600],showTrail:void 0===t.showTrail||t.showTrail,trailIntensity:t.trailIntensity||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.resizeTimer=null,this.wasRunningBeforeHide=!1,this.lastFrameTime=performance.now(),this.init()}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 default value instead.`),t.particleNumber=150)),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<0&&(console.warn(`Warning: particleSpeed (${i.particleSpeed}) is below minimum value (0). Using default 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 default value instead.`),t.particleSize=3)),void 0!==i.particleBlur&&(i.particleBlur>this.MAX_PARTICLE_BLUR?(console.warn(`Warning: particleBlur (${i.particleBlur}) exceeds maximum allowed value (${this.MAX_PARTICLE_BLUR}). Using maximum value instead.`),t.particleBlur=this.MAX_PARTICLE_BLUR):i.particleBlur<0&&(console.warn(`Warning: particleBlur (${i.particleBlur}) is below minimum value (0). Using default value instead.`),t.particleBlur=2)),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 default value instead.`),t.linkDistance=120)),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<0&&(console.warn(`Warning: lineWidth (${i.lineWidth}) is below minimum value (0). Using default 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 default value instead.`),t.lineOpacity=.3)),void 0!==i.trailIntensity&&(i.trailIntensity>this.MAX_TRAIL_INTENSITY?(console.warn(`Warning: trailIntensity (${i.trailIntensity}) exceeds maximum allowed value (${this.MAX_TRAIL_INTENSITY}). Using maximum value instead.`),t.trailIntensity=this.MAX_TRAIL_INTENSITY):i.trailIntensity<1&&(console.warn(`Warning: trailIntensity (${i.trailIntensity}) is below minimum value (1). Using default value instead.`),t.trailIntensity=2)),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,trailPositions:[]})}}updateParticles(i){const t=i/16.67;for(const i of this.particles)i.pulse+=i.pulseSpeed*t,i.pulse>2*Math.PI&&(i.pulse=0),this.config.showTrail&&(i.trailPositions.unshift({x:i.x,y:i.y}),i.trailPositions.length>10*this.config.trailIntensity&&(i.trailPositions.length=10*this.config.trailIntensity)),i.x+=i.vx*t,i.y+=i.vy*t,(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))}drawTrailEffect(){if(this.config.showTrail){this.ctx.save();for(const i of this.particles){if(i.trailPositions.length<2)continue;this.ctx.beginPath(),this.ctx.moveTo(i.trailPositions[0].x,i.trailPositions[0].y);for(let t=1;t<i.trailPositions.length;t++)this.ctx.lineTo(i.trailPositions[t].x,i.trailPositions[t].y);const t=1.2*i.size;this.ctx.lineWidth=t,this.ctx.lineCap="round",this.ctx.lineJoin="round";const s=i.trailPositions[0],e=i.trailPositions[i.trailPositions.length-1],a=this.ctx.createLinearGradient(s.x,s.y,e.x,e.y),n=this.parseColor(i.color),r=.35;a.addColorStop(0,`rgba(${n.r}, ${n.g}, ${n.b}, ${r})`),a.addColorStop(.3,`rgba(${n.r}, ${n.g}, ${n.b}, ${.6*r})`),a.addColorStop(.7,`rgba(${n.r}, ${n.g}, ${n.b}, ${.2*r})`),a.addColorStop(1,`rgba(${n.r}, ${n.g}, ${n.b}, 0)`),this.ctx.strokeStyle=a,this.ctx.stroke()}this.ctx.restore()}}parseColor(i){if(i.startsWith("rgba")){const t=i.match(/rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)/);if(t)return{r:parseInt(t[1]),g:parseInt(t[2]),b:parseInt(t[3]),a:parseFloat(t[4])}}else if(i.startsWith("rgb")){const t=i.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/);if(t)return{r:parseInt(t[1]),g:parseInt(t[2]),b:parseInt(t[3])}}else if(i.startsWith("#")){let t,s,e,a=i.replace("#","");if(3===a.length)t=parseInt(a[0]+a[0],16),s=parseInt(a[1]+a[1],16),e=parseInt(a[2]+a[2],16);else{if(6!==a.length)return{r:255,g:255,b:255};t=parseInt(a.substring(0,2),16),s=parseInt(a.substring(2,4),16),e=parseInt(a.substring(4,6),16)}return{r:t,g:s,b:e}}return{r:255,g:255,b:255}}drawParticles(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);let i=this.config.canvasBackgroundColor;if(i.startsWith("rgba")){const t=i.match(/rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)/);if(t){const s=t[1],e=t[2],a=t[3];parseFloat(t[4])<1&&(i=`rgb(${s}, ${e}, ${a})`)}}if(this.ctx.fillStyle=i,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height),this.drawTrailEffect(),this.config.showLine)for(let i=0;i<this.particles.length;i++)for(let t=i+1;t<this.particles.length;t++){const s=this.particles[i].x-this.particles[t].x,e=this.particles[i].y-this.particles[t].y,a=Math.sqrt(s*s+e*e);if(a<this.config.linkDistance){const s=this.config.lineOpacity*(1-a/this.config.linkDistance);this.ctx.strokeStyle=this.config.lineColor,this.ctx.globalAlpha=s,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.config.particleBlur>0&&(this.ctx.shadowColor=i.color,this.ctx.shadowBlur=4*this.config.particleBlur),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=performance.now(),t=i-this.lastFrameTime,s=Math.min(Math.max(t,1),100);this.updateParticles(s),this.drawParticles(),this.updateFPS(),this.lastFrameTime=i,this.animationId=requestAnimationFrame(()=>this.animate())}start(){this.isRunning||(this.isRunning=!0,this.lastFrameTime=performance.now(),this.animate())}pause(){this.isRunning=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}reset(){const i=this.isRunning;i&&this.pause(),this.createParticles(),i?this.start():this.drawParticles()}resize(){if(this.config.isBackground){const i=this.canvas.width,t=this.canvas.height,s=window.innerWidth,e=window.innerHeight;if(this.canvas.width=s,this.canvas.height=e,this.particles.length>0){const a=s/i,n=e/t;for(const i of this.particles)if(i.x*=a,i.y*=n,i.x=Math.max(0,Math.min(s,i.x)),i.y=Math.max(0,Math.min(e,i.y)),(i.x<=0||i.x>=s)&&(i.vx*=-1),(i.y<=0||i.y>=e)&&(i.vy*=-1),this.config.showTrail)for(let t=0;t<i.trailPositions.length;t++){const r=i.trailPositions[t];r.x*=a,r.y*=n,r.x=Math.max(0,Math.min(s,r.x)),r.y=Math.max(0,Math.min(e,r.y))}this.drawParticles()}else this.createParticles(),this.drawParticles()}}destroy(){this.pause(),this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}bindEvents(){window.addEventListener("resize",()=>{this.config.isBackground&&(this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.resize()},150))}),document.addEventListener("visibilitychange",()=>{document.hidden?(this.wasRunningBeforeHide=this.isRunning,this.isRunning&&this.pause()):(this.wasRunningBeforeHide&&this.start(),this.wasRunningBeforeHide=!1)})}}const s=t;return i.ParticleCanvas=t,i.default=s,Object.defineProperty(i,"__esModule",{value:!0}),i}({});
@@ -26,6 +26,8 @@ declare class ParticleCanvas {
26
26
  private readonly MAX_LINE_WIDTH;
27
27
  private readonly MAX_LINE_OPACITY;
28
28
  private readonly MAX_TRAIL_VALUE;
29
+ private readonly MAX_PARTICLE_BLUR;
30
+ private readonly MAX_TRAIL_INTENSITY;
29
31
  private lastFrameTime;
30
32
  /**
31
33
  * 初始化配置
@@ -59,6 +61,17 @@ declare class ParticleCanvas {
59
61
  * @param deltaTime 时间增量(毫秒)
60
62
  */
61
63
  private updateParticles;
64
+ /**
65
+ * 绘制粒子轨迹效果
66
+ * 在粒子后面绘制自然的光影拖尾效果
67
+ */
68
+ private drawTrailEffect;
69
+ /**
70
+ * 解析颜色字符串为RGB对象
71
+ * @param colorStr 颜色字符串
72
+ * @returns RGB对象
73
+ */
74
+ private parseColor;
62
75
  /**
63
76
  * 绘制粒子和连线
64
77
  * 在画布上渲染粒子系统
@@ -2,3 +2,4 @@ export * from './types';
2
2
  import ParticleCanvas from './ParticleCanvas';
3
3
  declare const ParticleCanvasPro: typeof ParticleCanvas;
4
4
  export default ParticleCanvasPro;
5
+ export { ParticleCanvas };
@@ -8,36 +8,49 @@ export interface Particle {
8
8
  originalColor: string;
9
9
  pulse: number;
10
10
  pulseSpeed: number;
11
+ trailPositions: any[];
11
12
  }
12
13
  export interface ParticleCanvasOptions {
13
14
  canvasContainer?: HTMLElement | string;
14
- isBackground?: boolean;
15
+ canvasSize?: [number, number];
15
16
  canvasBackgroundColor?: string;
17
+ isBackground?: boolean;
16
18
  particleNumber?: number;
17
19
  particleSpeed?: number;
18
20
  particleSize?: number;
19
21
  particleColor?: string | string[];
22
+ particleBlur?: number;
23
+ showTrail?: boolean;
24
+ trailIntensity?: number;
25
+ showLine?: boolean;
20
26
  lineWidth?: number;
21
27
  lineColor?: string;
22
28
  lineOpacity?: number;
23
29
  linkDistance?: number;
24
- showLinkLine?: boolean;
25
- canvasSize?: [number, number];
26
- trailValue?: number;
27
30
  }
28
31
  export interface ParticleCanvasConfig {
29
32
  canvasContainer: HTMLElement | string;
30
- isBackground: boolean;
33
+ canvasSize: [number, number];
31
34
  canvasBackgroundColor: string;
35
+ isBackground: boolean;
32
36
  particleNumber: number;
33
37
  particleSpeed: number;
34
38
  particleSize: number;
35
39
  particleColor: string | string[];
40
+ particleBlur: number;
41
+ showTrail: boolean;
42
+ trailIntensity: number;
43
+ showLine: boolean;
36
44
  lineWidth: number;
37
45
  lineColor: string;
38
46
  lineOpacity: number;
39
47
  linkDistance: number;
40
- showLinkLine: boolean;
41
- canvasSize: [number, number];
42
- trailValue: number;
48
+ }
49
+ export declare class ParticleCanvas {
50
+ constructor(options?: ParticleCanvasOptions);
51
+ start(): void;
52
+ pause(): void;
53
+ reset(): void;
54
+ resize(): void;
55
+ destroy(): void;
43
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "particle-canvas-pro",
3
- "version": "1.2.6",
3
+ "version": "1.3.1",
4
4
  "description": "🚀 🚀 一款基于requestAnimationFrame的高性能Canvas粒子系统,专为 Web 场景提供流畅、可配置的视觉动效方案,支持全屏背景与独立画布,提供实时控制、丰富视觉效果与流畅交互体验。",
5
5
  "main": "dist/bundle.cjs.js",
6
6
  "module": "dist/bundle.esm.js",